package com.xjrsoft.module.workflow.utils;


import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.convert.NumberChineseFormatter;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xjrsoft.common.constant.GlobalConstant;
import com.xjrsoft.common.enums.*;
import com.xjrsoft.common.exception.MyException;
import com.xjrsoft.common.model.generator.ComponentConfig;
import com.xjrsoft.common.utils.RedisUtil;
import com.xjrsoft.module.form.entity.FormDesignConfig;
import com.xjrsoft.module.form.entity.FormTemplate;
import com.xjrsoft.module.form.service.IFormTemplateService;
import com.xjrsoft.module.generator.constant.ComponentTypeConstant;
import com.xjrsoft.module.generator.entity.TableConfig;
import com.xjrsoft.module.generator.utils.GeneratorUtil;
import com.xjrsoft.module.liteflow.entity.LiteflowChain;
import com.xjrsoft.module.liteflow.service.ILiteflowChainService;
import com.xjrsoft.module.magicapi.service.IMagicApiService;
import com.xjrsoft.module.magicapi.vo.MagicApiInfoVo;
import com.xjrsoft.module.oa.utils.SendMessageUtil;
import com.xjrsoft.module.organization.entity.*;
import com.xjrsoft.module.organization.service.IDepartmentApprovalUserService;
import com.xjrsoft.module.organization.service.IUserService;
import com.xjrsoft.module.system.entity.Area;
import com.xjrsoft.module.system.entity.DictionaryDetail;
import com.xjrsoft.module.system.entity.MessageTemplate;
import com.xjrsoft.module.system.service.IAreaService;
import com.xjrsoft.module.system.service.IMessageTemplateService;
import com.xjrsoft.module.workflow.constant.WorkflowConstant;
import com.xjrsoft.module.workflow.entity.*;
import com.xjrsoft.module.workflow.model.*;
import com.xjrsoft.module.workflow.service.IWorkflowApproveRecordService;
import com.xjrsoft.module.workflow.service.IWorkflowRecordService;
import com.xjrsoft.module.workflow.service.IWorkflowSchemaService;
import com.yomahub.liteflow.core.FlowExecutor;
import lombok.SneakyThrows;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.camunda.bpm.engine.HistoryService;
import org.camunda.bpm.engine.ProcessEngines;
import org.camunda.bpm.engine.RepositoryService;
import org.camunda.bpm.engine.RuntimeService;
import org.camunda.bpm.engine.history.HistoricVariableInstance;
import org.camunda.bpm.engine.variable.VariableMap;
import org.camunda.bpm.model.bpmn.instance.*;
import org.camunda.bpm.model.xml.instance.ModelElementInstance;
import org.ssssssss.magicapi.core.service.MagicAPIService;
import org.ssssssss.magicapi.modules.db.model.PageResult;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * @Author: tzx
 * @Date: 2022/9/26 15:54
 */
public class WorkFlowUtil {

    /**
     * 替换占位符
     *
     * @param str            源字符串
     * @param workflowSchema 工作流模板信息
     * @param serialNumber   流水号  可不填
     * @return 替换后的字符串
     */
    public static String replacePlaceHolder(String str, WorkflowSchema workflowSchema, Long serialNumber, Long workflowSerialNumber) {
        SaSession tokenSession = StpUtil.getTokenSession();
        User user = tokenSession.get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());
        Department department = tokenSession.get(GlobalConstant.LOGIN_USER_DEPT_INFO_KEY, new Department());
        Post post = tokenSession.get(GlobalConstant.LOGIN_USER_POST_INFO_KEY, new Post());

        //流程流水号
        if (workflowSerialNumber != null && workflowSerialNumber != 0) {
            char zeroChar = '0';
            String serialNumberStr = StrUtil.toString(workflowSerialNumber);
            String fillStr = StringPool.EMPTY;

            if (str.contains(WorkflowConstant.SERIAL_NUBMER_FOUR_PLACEHOLDER)) {
                //4位数 前面补0
                fillStr = StrUtil.fillBefore(serialNumberStr, zeroChar, 4);
            } else if (str.contains(WorkflowConstant.SERIAL_NUBMER_FIVE_PLACEHOLDER)) {
                //4位数 前面补0
                fillStr = StrUtil.fillAfter(serialNumberStr, zeroChar, 5);
            } else if (str.contains(WorkflowConstant.SERIAL_NUBMER_SIX_PLACEHOLDER)) {
                //4位数 前面补0
                fillStr = StrUtil.fillAfter(serialNumberStr, zeroChar, 6);
            } else if (str.contains(WorkflowConstant.SERIAL_NUBMER_SEVEN_PLACEHOLDER)) {
                //4位数 前面补0
                fillStr = StrUtil.fillAfter(serialNumberStr, zeroChar, 7);
            } else if (str.contains(WorkflowConstant.SERIAL_NUBMER_EIGHT_PLACEHOLDER)) {
                //4位数 前面补0
                fillStr = StrUtil.fillAfter(serialNumberStr, zeroChar, 8);
            }

            if (StrUtil.isNotBlank(fillStr)) {
                str = str.replace(WorkflowConstant.SERIAL_NUBMER_FOUR_PLACEHOLDER, fillStr);
                str = str.replace(WorkflowConstant.SERIAL_NUBMER_FIVE_PLACEHOLDER, fillStr);
                str = str.replace(WorkflowConstant.SERIAL_NUBMER_SIX_PLACEHOLDER, fillStr);
                str = str.replace(WorkflowConstant.SERIAL_NUBMER_SEVEN_PLACEHOLDER, fillStr);
                str = str.replace(WorkflowConstant.SERIAL_NUBMER_EIGHT_PLACEHOLDER, fillStr);
            }

        }
        if (str.contains(WorkflowConstant.TEMPLATE_CATEGORY_PLACEHOLDER) && ObjectUtil.isNotNull(workflowSchema.getCategory())) {
            RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);
            List<DictionaryDetail> detailList = redisUtil.get(GlobalConstant.DIC_DETAIL_CACHE_KEY, new TypeReference<List<DictionaryDetail>>() {
            });

            Optional<DictionaryDetail> dictionaryDetail = detailList.stream().filter(x -> x.getId().equals(workflowSchema.getCategory())).findFirst();

            if (dictionaryDetail.isPresent()) {
                str = str.replace(WorkflowConstant.TEMPLATE_CATEGORY_PLACEHOLDER, StrUtil.toString(dictionaryDetail.get().getName()));
            } else {
                str = str.replace(WorkflowConstant.TEMPLATE_CATEGORY_PLACEHOLDER, StrUtil.toString(workflowSchema.getCategory()));
            }
        }

        if(str.contains(WorkflowConstant.TEMPLATE_REMARK_PLACEHOLDER) && StrUtil.isNotBlank(workflowSchema.getRemark())){ //workflowSchema.getRemark()可能为空
            str = str.replace(WorkflowConstant.TEMPLATE_REMARK_PLACEHOLDER, workflowSchema.getRemark());
        }

        if(StrUtil.isNotBlank(post.getName())){
            str = str.replace(WorkflowConstant.INITIATOR_POST_NAME_PLACEHOLDER, post.getName());
        }else {
            str = str.replace(WorkflowConstant.INITIATOR_POST_NAME_PLACEHOLDER, StringPool.EMPTY);
        }

        if (str.contains(WorkflowConstant.RANDOM_DASH)){
            str = str.replace(WorkflowConstant.RANDOM_DASH,StringPool.DASH);
        }

        return str.replace(WorkflowConstant.TEMPLATE_CODE_PLACEHOLDER, workflowSchema.getCode())
                .replace(WorkflowConstant.TEMPLATE_NAME_PLACEHOLDER, workflowSchema.getName())
                .replace(WorkflowConstant.TASK_ID_PLACEHOLDER, workflowSchema.getDefinitionId())
                .replace(WorkflowConstant.INITIATOR_ID_PLACEHOLDER, user.getId().toString())
                .replace(WorkflowConstant.INITIATOR_USER_NAME_PLACEHOLDER, user.getName())
                .replace(WorkflowConstant.INITIATOR_CODE_PLACEHOLDER, user.getCode())
                .replace(WorkflowConstant.INITIATOR_MOBILE_PLACEHOLDER, user.getMobile())
                .replace(WorkflowConstant.INITIATOR_DEPT_NAME_PLACEHOLDER, department.getName())
                .replace(WorkflowConstant.YYYYMMDDHHMMSS_24_PLACEHOLDER, DateUtil.format(LocalDateTime.now(), GlobalConstant.YYYY_MM_DD_HH_MM_SS_24))
                .replace(WorkflowConstant.YYYYMMDDHHMMSS_12_PLACEHOLDER, DateUtil.format(LocalDateTime.now(), GlobalConstant.YYYY_MM_DD_HH_MM_SS_12))
                .replace(WorkflowConstant.YYYYMMDD_PLACEHOLDER, DateUtil.format(LocalDateTime.now(), GlobalConstant.YYYY_MM_DD))
                .replace(WorkflowConstant.HHMMSS_24_PLACEHOLDER, DateUtil.format(LocalDateTime.now(), GlobalConstant.HH_MM_SS_24))
                .replace(WorkflowConstant.HHMMSS_12_PLACEHOLDER, DateUtil.format(LocalDateTime.now(), GlobalConstant.HH_MM_SS_12))
                .replace(WorkflowConstant.RANDOM_2_PLACEHOLDER, RandomUtil.randomNumbers(2))
                .replace(WorkflowConstant.RANDOM_2_MIX_PLACEHOLDER, RandomUtil.randomString(2))
                .replace(WorkflowConstant.RANDOM_4_PLACEHOLDER, RandomUtil.randomNumbers(4))
                .replace(WorkflowConstant.RANDOM_4_MIX_PLACEHOLDER, RandomUtil.randomString(4))
                .replace(WorkflowConstant.RANDOM_6_PLACEHOLDER, RandomUtil.randomNumbers(6))
                .replace(WorkflowConstant.RANDOM_6_MIX_PLACEHOLDER, RandomUtil.randomString(6))
                .replace(WorkflowConstant.RANDOM_8_PLACEHOLDER, RandomUtil.randomNumbers(8))
                .replace(WorkflowConstant.RANDOM_8_MIX_PLACEHOLDER, RandomUtil.randomString(8))
                .replace(WorkflowConstant.SERIAL_NUBMER_PLACEHOLDER, StrUtil.toString(serialNumber))
                .replace(StringPool.HASH, StringPool.EMPTY)
                .replace(StringPool.LEFT_BRACE, StringPool.EMPTY)
                .replace(StringPool.RIGHT_BRACE, StringPool.EMPTY);

    }

    /**
     * 生成流程名称
     *
     * @param workflowSchema
     * @param workflowSchemaConfig
     * @param workflowSerialNumber
     * @return
     */
    public static String generatorProcessName(WorkflowSchema workflowSchema, WorkflowSchemaConfig workflowSchemaConfig, Long workflowSerialNumber) {

        if (workflowSchemaConfig.getProcessConfig().getNameRuleConfigs().size() == 0) {
            return workflowSchema.getName();
        }
        String nameTemplate = workflowSchemaConfig.getProcessConfig().getNameRuleConfigs().stream().map(NameRuleConfig::getKey).map(String::valueOf).collect(Collectors.joining(StringPool.SPACE));

        return WorkFlowUtil.replacePlaceHolder(nameTemplate, workflowSchema, workflowSerialNumber, workflowSerialNumber);
    }

    /**
     * 根据memberConfig  获取所有userIds
     * 例如查审批人  推送人   权限 等
     *
     * @return
     */
    public static List<Long> getUserIdsByMemberConfig(List<MemberConfig> memberConfigs, List<Map<String, Object>> childNodeConfig, String processId) {
        List<Long> result = new ArrayList<>();

        if (memberConfigs.size() == 0) {
            return result;
        }

        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);

        //如果有选择角色
        List<UserRoleRelation> userRoleRelations = null;
        //如果有选择用户
        List<User> users = null;
        //如果选择岗位
        List<Post> posts = null;
        List<UserPostRelation> userPostRelations = null;

        List<UserDeptRelation> userDeptRelations = null;

        //部门数据
        List<Department> departments = null;

//        Optional<LeaderConfig> maxLevel = memberConfigs.parallelStream().filter(m -> m.getMemberType() == WorkflowMemberType.LEADER.getCode()).map(MemberConfig::getLeaderConfig).max(Comparator.comparing(LeaderConfig::getLevel));


        for (MemberConfig memberConfig : memberConfigs) {
            //如果是用户  memberlistconfig  存储的就是 用户id   直接  添加到返回值中
            if (memberConfig.getMemberType() == WorkflowMemberType.USER.getCode()) {
                result.add(Convert.toLong(memberConfig.getId()));
            }
            //如果是角色
            // 从 缓存中获取到所有角色数据
            // 根据所有角色id   从 缓存中获取 所有 用户角色关联信息
            // 获取到所有用户id  添加到返回值中
            if (memberConfig.getMemberType() == WorkflowMemberType.ROLE.getCode()) {

                if (ObjectUtil.isNull(userRoleRelations)) {
                    userRoleRelations = redisUtil.get(GlobalConstant.USER_ROLE_RELATION_CACHE_KEY, new TypeReference<List<UserRoleRelation>>() {
                    });
                }

                //获取到所有角色的关联用户
                List<Long> userIds = userRoleRelations.stream().filter(x -> x.getRoleId().equals(Convert.toLong(memberConfig.getId()))).map(UserRoleRelation::getUserId).collect(Collectors.toList());
                result.addAll(userIds);
            }
            //根据岗位获取用户
            if (memberConfig.getMemberType() == WorkflowMemberType.POST.getCode()) {

                if (ObjectUtil.isNull(userPostRelations)) {
                    userPostRelations = redisUtil.get(GlobalConstant.USER_POST_RELATION_CACHE_KEY, new TypeReference<List<UserPostRelation>>() {
                    });
                }
                List<Long> userIds = userPostRelations.stream().filter(p -> ObjectUtil.equals(Convert.toLong(memberConfig.getId()), p.getPostId())).map(UserPostRelation::getUserId).collect(Collectors.toList());
                result.addAll(userIds);
            }
            //指定节点审批人
            if (memberConfig.getMemberType() == WorkflowMemberType.APPROVE.getCode()) {

                //如果是选择的开始节点
                if (memberConfig.getId().equals(WorkflowConstant.START_NODE_DEFAULT_ID)) {
                    //将map 转为 java类  默认只有用户任务节点才有审批人
                    RuntimeService runtimeService = ProcessEngines.getDefaultProcessEngine().getRuntimeService();

                    Object startUserIdObj = runtimeService.getVariable(processId, WorkflowConstant.PROCESS_START_USER_ID_KEY);
                    Long startUserId = Convert.toLong(startUserIdObj);
                    result.add(startUserId);
                    continue;
                }

                //必须是用户任务节点
                Optional<Map<String, Object>> userTaskConfigMapOp = childNodeConfig.stream().filter(x -> x.containsValue(memberConfig.getId())).findFirst();
                if (!userTaskConfigMapOp.isPresent()) {
                    continue;
                }
                //    将map 转为 java类
                UserTaskConfig userTaskConfig = Convert.convert(UserTaskConfig.class, userTaskConfigMapOp.get());
                List<Long> approverUserIds = getUserIdsByMemberConfig(userTaskConfig.getApproverConfigs(), childNodeConfig, processId);
                result.addAll(approverUserIds);

            }
            //上级领导
            if (memberConfig.getMemberType() == WorkflowMemberType.LEADER.getCode()) {

                if (ObjectUtil.isNull(posts)) {
                    posts = redisUtil.get(GlobalConstant.POST_CACHE_KEY, new TypeReference<List<Post>>() {
                    });
                }
                if (ObjectUtil.isNull(users)) {
                    users = redisUtil.get(GlobalConstant.USER_CACHE_KEY, new TypeReference<List<User>>() {
                    });
                }

                LeaderConfig leaderConfig = memberConfig.getLeaderConfig();
                //获取到节点配置
                Optional<Map<String, Object>> nodeMap = childNodeConfig.stream().filter(x -> x.get(GlobalConstant.DEFAULT_PK).equals(leaderConfig.getNodeId())).findFirst();

                if (!nodeMap.isPresent()) {
                    return result;
                }

                //如果是开始节点
                if (leaderConfig.getNodeId().equals(WorkflowConstant.START_NODE_DEFAULT_ID)) {
                    //将map 转为 java类  默认只有用户任务节点才有审批人
                    RuntimeService runtimeService = ProcessEngines.getDefaultProcessEngine().getRuntimeService();

                    Object startUserIdObj = runtimeService.getVariable(processId, WorkflowConstant.PROCESS_START_USER_ID_KEY);
                    Long startUserId = Convert.toLong(startUserIdObj);

                    //获取到发起人用户信息
                    Optional<User> startUserOp = users.stream().filter(x -> x.getId().equals(startUserId)).findFirst();
                    if (!startUserOp.isPresent()) {
                        return result;
                    }

                    Long postId;
                    //如果发起人id等于当前登陆人id
                    if (startUserId == StpUtil.getLoginIdAsLong()) {
                        Object postIdObj = runtimeService.getVariable(processId, WorkflowConstant.PROCESS_START_USER_POST_ID_KEY);
                        postId = Convert.toLong(postIdObj);
                    } else {
                        //获取当前发起的身份
                        HistoryService historyService = ProcessEngines.getDefaultProcessEngine().getHistoryService();
                        HistoricVariableInstance historicVariableInstance = historyService.createHistoricVariableInstanceQuery().processInstanceId(processId).variableName(WorkflowConstant.PROCESS_START_USER_POST_ID_KEY).singleResult();

                        postId = Convert.toLong(historicVariableInstance.getValue());
                    }

                    Optional<Post> thisApproveOp = posts.stream().filter(x -> x.getId().equals(postId)).findFirst();
                    if (!thisApproveOp.isPresent()) {
                        return result;
                    }

                    Post thisUserPost = thisApproveOp.get();

                    for (int i = 1; i <= leaderConfig.getLevel(); i++) {

                        Post finalThisUserPost = thisUserPost;
                        Optional<Post> parentPostOp = posts.stream().filter(x -> finalThisUserPost.getParentId().equals(x.getId())).findFirst();

                        //如果当前循环次数 找不到上级
                        if (!parentPostOp.isPresent()) {
                            return result;
                        } else {
                            thisUserPost = parentPostOp.get();
                        }


                        //当前级别 跟 循环次数一致  就把当前所查出来的岗位 所属人员 加入到 leaderUserIds
                        if (i == leaderConfig.getLevel()) {
                            //找到当前角色下的所有人员 id 存入 result
                            Post post = parentPostOp.get();
                            userPostRelations = redisUtil.get(GlobalConstant.USER_POST_RELATION_CACHE_KEY, new TypeReference<List<UserPostRelation>>() {
                            });
                            List<Long> leaderUserIds = userPostRelations.stream().filter(x -> ObjectUtil.equals(post.getId(), x.getPostId())).map(UserPostRelation::getUserId).collect(Collectors.toList());
//                            List<Long> leaderUserIds = users.stream().filter(x -> ObjectUtil.equals(post.getId(),x.getPostId())).map(User::getId).collect(Collectors.toList());
                            result.addAll(leaderUserIds);
                        }


                    }

//                    Long finalCurrentPostParentId = thisApproveOp.get().getParentId();
//                    for (int i = 0; i < leaderConfig.getLevel(); i++) {
//                        for (Post post : posts) {
//                            if (post.getId().equals(finalCurrentPostParentId) && leaderConfig.getLevel() == i) {
//                                final long parentId = finalCurrentPostParentId;
//                                List<Long> leaderUserIds = users.stream().filter(u -> u.getPostId().equals(parentId)).map(User::getId).collect(Collectors.toList());
//                                result.addAll(leaderUserIds);
//                                finalCurrentPostParentId = post.getParentId();
//                            }
//                        }
//                    }
                    return result;

                } else {
                    //将map 转为 java类  默认只有用户任务节点才有审批人
                    UserTaskConfig userTaskConfig = Convert.convert(UserTaskConfig.class, nodeMap.get());
//                    List<MemberConfig> approverConfigs = userTaskConfig.getApproverConfigs();

                    IWorkflowApproveRecordService workflowApproveRecordService = SpringUtil.getBean(IWorkflowApproveRecordService.class);

                    //获取到当前流程的当前task 的审批记录  可能涉及到 驳回、流程画图流转回来、多实例 等清空 可能会有多条
                    //大部分是一条 默认根据id 倒叙排序 取最后一条数据  代表最新的审批人
                    List<WorkflowApproveRecord> list = workflowApproveRecordService.list(Wrappers.lambdaQuery(WorkflowApproveRecord.class)
                            .eq(WorkflowApproveRecord::getProcessId, processId)
                            .eq(WorkflowApproveRecord::getTaskDefinitionKey, userTaskConfig.getId())
                            .orderByDesc(WorkflowApproveRecord::getId)
                    );

                    //如果查不到审批记录  默认不走下面逻辑
                    if (ObjectUtil.isNull(list) || list.size() == 0) {
                        break;
                    }
                    //获取到最新的一条审批记录中 所存储的 岗位
                    Long approveUserPostId = list.get(0).getApproveUserPostId();

                    Optional<Post> thisApproveOp = posts.stream().filter(x -> x.getId().equals(approveUserPostId)).findFirst();
                    // 如果postId 找不到信息  停止循环
                    if (!thisApproveOp.isPresent()) {
                        break;
                    }
                    Long finalCurrentPostParentId = thisApproveOp.get().getParentId();

                    if (ObjectUtil.isNull(userPostRelations)) {
                        userPostRelations = redisUtil.get(GlobalConstant.USER_POST_RELATION_CACHE_KEY, new TypeReference<List<UserPostRelation>>() {
                        });
                    }

                    for (int i = 1; i <= leaderConfig.getLevel(); i++) {
                        for (Post post : posts) {
                            if (post.getId().equals(finalCurrentPostParentId) && leaderConfig.getLevel() == i) {
                                final long parentId = finalCurrentPostParentId;

                                List<Long> leaderUserIds = userPostRelations.stream().filter(x -> x.getPostId().equals(parentId)).map(UserPostRelation::getUserId).collect(Collectors.toList());
//                                List<Long> leaderUserIds = users.stream().filter(u -> u.getPostId().equals(parentId)).map(User::getId).collect(Collectors.toList());
                                result.addAll(leaderUserIds);
                                finalCurrentPostParentId = post.getParentId();
                            }
                        }
                    }
                }


            }
            //表单字段
            if (memberConfig.getMemberType() == WorkflowMemberType.FORM_FIELD.getCode()) {
                //将map 转为 java类  默认只有用户任务节点才有审批人
                RuntimeService runtimeService = ProcessEngines.getDefaultProcessEngine().getRuntimeService();

                FormFieldConfig formFieldConfigs = memberConfig.getFormFieldConfig();

                Object formDataObj = runtimeService.getVariable(processId, formFieldConfigs.getFormKey());
                Map<String, Object> formData = Convert.toMap(String.class, Object.class, formDataObj);

                Object fieldValue = formData.get(formFieldConfigs.getFormField());

                //将审批的值插入到审批人result中
                buildApproveIdResult(fieldValue,result);

            }

            if (memberConfig.getMemberType() == WorkflowMemberType.API.getCode()){//api审批人接口数据
                IMagicApiService magicApiService = SpringUtil.getBean(IMagicApiService.class);
                MagicAPIService magicAPIService = SpringUtil.getBean(MagicAPIService.class);
                ApiConfig apiConfig = memberConfig.getApiConfig();
                MagicApiInfoVo info = magicApiService.info(apiConfig.getId());
                Map<String, Object> params = new HashMap<>();
                RuntimeService runtimeService = ProcessEngines.getDefaultProcessEngine().getRuntimeService();
                Object processParamObj = runtimeService.getVariable(processId, WorkflowConstant.PROCESS_PARAM_KEY);
                Object varObj = runtimeService.getVariables(processId);
                Map<String, Object> varMap = Convert.toMap(String.class, Object.class, varObj);
                Map<String, Object> processParam = Convert.toMap(String.class, Object.class, processParamObj);
                Long serialNumber = MapUtil.get(varMap, WorkflowConstant.PROCESS_SERIAL_NUMBER_KEY, Long.class);

                Long schemaId = MapUtil.get(varMap, WorkflowConstant.PROCESS_SCHEMA_ID_KEY, Long.class);
                IWorkflowSchemaService workflowSchemaService = SpringUtil.getBean(IWorkflowSchemaService.class);
                WorkflowSchema workflowSchema = workflowSchemaService.getOne(Wrappers.lambdaQuery(WorkflowSchema.class).eq(WorkflowSchema::getId, schemaId));

                for (ApiRequestParamsConfig requestParamsConfig : apiConfig.getRequestParamsConfigs()) {
                    WorkFlowUtil.initApiParams(processParam, varMap, params, requestParamsConfig,workflowSchema,processId);
                }
                for (ApiRequestParamsConfig requestHeaderConfig : apiConfig.getRequestHeaderConfigs()) {
                    WorkFlowUtil.initApiParams(processParam, varMap, params, requestHeaderConfig,workflowSchema,processId);
                }
                for (ApiRequestParamsConfig requestBodyConfig : apiConfig.getRequestBodyConfigs()) {
                    WorkFlowUtil.initApiParams(processParam, varMap, params, requestBodyConfig,workflowSchema,processId);
                }
                Object approveUserIds = magicAPIService.execute(info.getMethod(), info.getPath(), params);

                //将审批的值插入到审批人result中
                buildApproveIdResult(approveUserIds,result);
            }

            if (memberConfig.getMemberType() == WorkflowMemberType.APPROVAL_SPECIALIST.getCode()) {//审批专员数据
                //审批专员的限制条件
                List<String> limit = memberConfig.getLimit();

                //审批专员的id
                Long approvalSpecialistId = Convert.toLong(memberConfig.getId());
                //找到对应的审批专员、部门所对应的人员，如果存在，就加入到审批人中去。
                IDepartmentApprovalUserService departmentApprovalUserService = SpringUtil.getBean(IDepartmentApprovalUserService.class);
                List<DepartmentApprovalUser> list = departmentApprovalUserService.list(Wrappers.<DepartmentApprovalUser>lambdaQuery().eq(DepartmentApprovalUser::getApprovalSpecialistId, approvalSpecialistId));

                if (ObjectUtil.isNotNull(limit) && limit.size() > 0) {//限制条件为空走不限制逻辑
                    //获取发起人所属组织id
                    if (ObjectUtil.isNull(users)) {
                        users = redisUtil.get(GlobalConstant.USER_CACHE_KEY, new TypeReference<List<User>>() {
                        });
                    }
                    if (ObjectUtil.isNull(departments)) {
                        departments = redisUtil.get(GlobalConstant.DEP_CACHE_KEY, new TypeReference<List<Department>>() {
                        });

                        //将map 转为 java类  默认只有用户任务节点才有审批人
                        RuntimeService runtimeService = ProcessEngines.getDefaultProcessEngine().getRuntimeService();

                        Object startUserIdObj = runtimeService.getVariable(processId, WorkflowConstant.PROCESS_START_USER_ID_KEY);
                        Long startUserId = Convert.toLong(startUserIdObj);

                        //获取到发起人用户信息
                        Optional<User> startUserOp = users.stream().filter(x -> x.getId().equals(startUserId)).findFirst();
                        if (!startUserOp.isPresent()) {
                            return result;
                        }

                        //获取发起人所属的部门
                        if (ObjectUtil.isNull(userDeptRelations)) {
                            userDeptRelations = redisUtil.get(GlobalConstant.USER_DEPT_RELATION_CACHE_KEY, new TypeReference<List<UserDeptRelation>>() {
                            });
                        }

                        List<UserDeptRelation> userDeptRelationList = userDeptRelations.stream().filter(x -> x.getUserId().equals(startUserId)).collect(Collectors.toList());
                        List<Long> userDeptIds = new ArrayList<>();
                        if (userDeptRelationList.size() > 0){
                            userDeptIds = userDeptRelationList.stream().map(UserDeptRelation::getDeptId).collect(Collectors.toList());
                        }else {
                            throw new MyException("当前用户没有所属的组织");
                        }

                        //需要的部门id
                        List<Long> deptIds = new ArrayList<>();

                        for (Long deptId : userDeptIds) {

                            Optional<Department> departmentOptional = departments.stream().filter(x -> x.getId().equals(deptId)).findFirst();
                            if (!departmentOptional.isPresent()) {
                                return result;
                            }

                            Department department = departmentOptional.get();
                            //获取部门的层级
                            String hierarchy = department.getHierarchy();

                            if (StrUtil.isNotBlank(hierarchy)) {
                                //部门层级，使用-分割开，就是所有的上级部门ids
                                String[] split = hierarchy.split(StringPool.DASH);
                                if (split.length > 0) {
                                    for (String s : limit) {//循环限制条件

                                        if (s.equals("nolimit")) {//不限,直接结束循环，找出所有的审批专员进行审批
                                            List<Long> userList = list.stream().filter(x->ObjectUtil.isNotEmpty(x.getUserId())).map(DepartmentApprovalUser::getUserId).collect(Collectors.toList());
                                            //加入到审批人中
                                            result.addAll(userList);
                                            break;
                                        }
                                        if (s.equals("same")) {//发起人所属组织，跳出当前循环，进行下一次循环
                                            deptIds.add(department.getId());
                                            continue;
                                        }
                                        if (s.equals("sameS1")) {//发起人上级组织
                                            if (split.length > 1){
                                                Long hierarchyId = Convert.toLong(split[split.length - 2]);
                                                deptIds.add(hierarchyId);
                                            }
                                            continue;
                                        }
                                        if (s.equals("sameS2")) {//发起人上二级组织
                                            if (split.length > 2){
                                                Long hierarchyId = Convert.toLong(split[split.length - 3]);
                                                deptIds.add(hierarchyId);
                                            }
                                            continue;
                                        }
                                        if (s.equals("sameS3")) {//上三级组织
                                            if (split.length > 3){
                                                Long hierarchyId = Convert.toLong(split[split.length - 4]);
                                                deptIds.add(hierarchyId);
                                            }
                                            continue;
                                        }
                                        if (s.equals("sameS4")) {//上四级组织
                                            if (split.length > 4){
                                                Long hierarchyId = Convert.toLong(split[split.length - 5]);
                                                deptIds.add(hierarchyId);
                                            }
                                            continue;
                                        }
                                        if (s.equals("sameS5")) {//上五级组织
                                            if (split.length > 5){
                                                Long hierarchyId = Convert.toLong(split[split.length - 6]);
                                                deptIds.add(hierarchyId);
                                            }
                                            continue;
                                        }
                                        if (s.equals("sameS6")) {//上六级组织
                                            if (split.length > 6){
                                                Long hierarchyId = Convert.toLong(split[split.length - 7]);
                                                deptIds.add(hierarchyId);
                                            }
                                            continue;
                                        }
                                        if (s.equals("sameMax")) {//发起人所属最高级组织
                                            Long hierarchyId = Convert.toLong(split[0]);
                                            deptIds.add(hierarchyId);
                                        }
                                    }
                                }
                            }
                        }

                        //上级组织配置ids，找到对应组织的审批专员
                        if (deptIds.size() > 0){
                           if (list.size() > 0){
                                List<DepartmentApprovalUser> collect = list.stream().filter(x -> deptIds.contains(x.getDepartmentId())).collect(Collectors.toList());
                                if (collect.size() > 0){
                                    List<Long> userList = collect.stream().filter(x->ObjectUtil.isNotEmpty(x.getUserId())).map(DepartmentApprovalUser::getUserId).collect(Collectors.toList());
                                    //加入到审批人中
                                    result.addAll(userList);
                                }
                            }
                        }

                    }
                }else {//如果没选择限制条件，走不限制逻辑
                    //不限,直接结束循环，找出所有的审批专员进行审批
                    List<Long> userList = list.stream().filter(x->ObjectUtil.isNotEmpty(x.getUserId())).map(DepartmentApprovalUser::getUserId).collect(Collectors.toList());
                    //加入到审批人中
                    result.addAll(userList);
                    break;
                }
            }


        }
        return result;
    }

    /**
     * 根据获取到的审批人ids添加道审批人数组中
     * @param fieldValue 审批人ids
     * @param result 审批人数组
     */
    private static void buildApproveIdResult(Object fieldValue, List<Long> result){
        //可能转换不了 捕获错误。
        try {
            if (fieldValue instanceof String) {
                //如果包含逗号 表示 可能多个
                String approveStr = StrUtil.toString(fieldValue);
                if (approveStr.contains(StringPool.COMMA)) {
                    String[] approveSplit = approveStr.split(StringPool.COMMA);

                    for (String approve : approveSplit) {
                        Long approveId = Convert.toLong(approve);
                        result.add(approveId);
                    }
                } else {
                    Long approveId = Convert.toLong(fieldValue);
                    result.add(approveId);
                }
            } else {
                Long approveId = Convert.toLong(fieldValue);
                result.add(approveId);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * approveUserIds  获取所有所有委托userids
     * 只用于查询审批人 包括委托人
     *
     * @return
     */
    public static List<Long> getDelegateUserIdsByApproveUserId(List<Long> approveUserIds, List<WorkflowDelegate> delegateList, Long schemaId) {

        List<Long> result = new ArrayList<>(approveUserIds);
        for (Long approveUserId : approveUserIds) {
            List<WorkflowDelegate> thisUserDelegate = delegateList.stream().filter(d -> d.getUserId().equals(approveUserId) && d.getSchemaIds().contains(schemaId.toString())).collect(Collectors.toList());

            for (WorkflowDelegate workflowDelegate : thisUserDelegate) {
                String[] split = workflowDelegate.getDelegateUserIds().split(StringPool.COMMA);
                List<Long> delegateUserIds = Arrays.stream(split).map(Convert::toLong).collect(Collectors.toList());

                result.addAll(delegateUserIds);
            }

        }


        return result;
    }


    /**
     * 获取流程线的所有值  存入变量
     *
     * @param processDefinitionId  流程定义id
     * @param workflowSchemaConfig schema
     * @param nodeId               nodeId当前节点id（key）
     * @param variableMap          变量Map
     */
    @Deprecated
    public static void getFlowConditionVar(String processDefinitionId, WorkflowSchemaConfig workflowSchemaConfig, String nodeId, VariableMap variableMap, Map<String, Map<String, Object>> formData) {

        RepositoryService repositoryService = ProcessEngines.getDefaultProcessEngine().getRepositoryService();

        //找到当前节点 element 对象
        ModelElementInstance currentElement = repositoryService.getBpmnModelInstance(processDefinitionId).getModelElementById(nodeId);
        //找到当前用户节点的子节点 是网关的
        Collection<Gateway> gateways = currentElement.getChildElementsByType(Gateway.class);

        //如果下级节点有网关
        if (gateways.size() > 0) {
            //存储有哪些变量要 存入到工作流数据表中
            List<String> allFlowVarKeys = new ArrayList<>();
            //存储有哪些变量需要从表单的某个字段获取值
            List<String> allFlowVarBindFormField = new ArrayList<>();
            //所有流程线配置
            List<ConditionConfig> conditionConfigs = new ArrayList<>();
            //流程线的key
            List<String> allFlowKey = new ArrayList<>();

            //遍历所有网关
            for (Gateway gateway : gateways) {
                //找到网关所有的下级连接线 的id
                List<String> gatewayFlowIds = gateway.getOutgoing().stream().map(BaseElement::getId).collect(Collectors.toList());

                //遍历所有连接线的配置
                for (String gatewayFlowId : gatewayFlowIds) {
                    Optional<Map<String, Object>> sequenceflowConfigMapOp = workflowSchemaConfig.getChildNodeConfig().stream().filter(x -> x.containsValue(gatewayFlowId)).findFirst();

                    //流程线 流转条件 变量名字 取名规则 form:{nodeId}:{formId}
                    sequenceflowConfigMapOp.ifPresent(flow -> {
                        SequenceFlowConfig sequenceFlowConfig = Convert.convert(SequenceFlowConfig.class, flow);

                        //获取到所有需要的  变量key  和绑定表单字段
                        for (ConditionConfig config : sequenceFlowConfig.getConditionConfigs()) {
                            conditionConfigs.add(config);
                            allFlowKey.add(gatewayFlowId);
                            allFlowVarKeys.add(WorkflowConstant.PROCESS_FORMDATA_PREFIX_KEY + config.getFormId());
                            allFlowVarBindFormField.add(config.getFormField());
                        }

                    });
                }
            }


            //key === flow:{flowId}:{nodeId}:{formId}:{formField}   value == 需要存入的值
            for (int i = 0; i < allFlowKey.size(); i++) {
                Object formDataObject = formData.get(allFlowVarKeys.get(i));
                Map<String, Object> formDataMap = Convert.toMap(String.class, Object.class, formDataObject);
                if (formDataMap != null) {
                    Object fieldValue = MapUtil.get(formDataMap, allFlowVarBindFormField.get(i), Object.class);
                    ConditionConfig config = conditionConfigs.get(i);

                    String key = WorkflowConstant.FLOW_PARAM_PREFIX_KEY +
                            allFlowKey.get(i) + StringPool.COLON +
                            config.getNodeId() + StringPool.COLON + config.getFormId() + StringPool.COLON +
                            config.getFormField();


                    variableMap.putValue(key, fieldValue);

                }

            }


        }
    }

    /**
     * 根据id 从 工作流模板配置 获取 节点的配置信息
     *
     * @param id              节点id
     * @param childNodeConfig 所有节点配置
     * @param clazz           类型
     * @param <T>             配置类型
     * @return
     */
    public static <T> T getNodeConfig(String id, List<Map<String, Object>> childNodeConfig, Class<T> clazz) {
        Optional<Map<String, Object>> configOp = childNodeConfig.stream().filter(c -> c.containsValue(id)).findFirst();
        return configOp.map(stringObjectMap -> Convert.convert(clazz, stringObjectMap)).orElse(null);
    }


    /**
     * 执行参数赋值
     *
     * @param assignmentConfig 赋值配置
     * @param processParam     流程参数
     * @param varMap           流程变量
     */
    public static void invokeParamAssignment(AssignmentConfig assignmentConfig, Map<String, Object> processParam, Map<String, Object> varMap, WorkflowSchema workflowSchema,String processId) {
        List<ParamAssignmentConfig> paramAssignmentConfigs = assignmentConfig.getParamAssignmentConfigs();

        for (ParamAssignmentConfig paramAssignmentConfig : paramAssignmentConfigs) {
            //如果是值
            if (paramAssignmentConfig.getType() == ParamAssignmentType.VALUE.getCode()) {
                if (processParam.containsKey(paramAssignmentConfig.getTarget())) {
                    processParam.put(paramAssignmentConfig.getTarget(), paramAssignmentConfig.getValue());
                }
            }
            //如果是变量
            if (paramAssignmentConfig.getType() == ParamAssignmentType.VAR.getCode()) {

                Long serialNumber = MapUtil.get(varMap, WorkflowConstant.PROCESS_SERIAL_NUMBER_KEY, Long.class);

                String newStr = WorkFlowUtil.replacePlaceHolder(paramAssignmentConfig.getVarValue(), workflowSchema, serialNumber, 0L);

                processParam.put(paramAssignmentConfig.getTarget(), newStr);
            }
            //如果是表单
            if (paramAssignmentConfig.getType() == ParamAssignmentType.FORM.getCode()) {

                //使用3下划线切割
                String[] split = paramAssignmentConfig.getFormConfig().getKey().split(StringPool.UNDERSCORE + StringPool.UNDERSCORE + StringPool.UNDERSCORE);
                String formKey = split[1];
                Map<String, Object> formData = MapUtil.get(varMap, formKey, new TypeReference<Map<String, Object>>() {
                });
                Object fieldValue = MapUtil.get(formData, paramAssignmentConfig.getFormConfig().getFormField(), Object.class);

                processParam.put(paramAssignmentConfig.getTarget(), fieldValue);
            }

            //如果是api
            if (paramAssignmentConfig.getType() == ParamAssignmentType.API.getCode()) {

                IMagicApiService magicApiService = SpringUtil.getBean(IMagicApiService.class);
                MagicAPIService magicAPIService = SpringUtil.getBean(MagicAPIService.class);

                ApiConfig apiConfig = paramAssignmentConfig.getApiConfig();

                MagicApiInfoVo info = magicApiService.info(apiConfig.getId());
//                Long serialNumber = MapUtil.get(varMap, WorkflowConstant.PROCESS_SERIAL_NUMBER_KEY, Long.class);


                Map<String, Object> params = new HashMap<>();
                for (ApiRequestParamsConfig requestParamsConfig : apiConfig.getRequestParamsConfigs()) {
                    initApiParams(processParam, varMap, params, requestParamsConfig,workflowSchema,processId);
                }
                for (ApiRequestParamsConfig requestHeaderConfig : apiConfig.getRequestHeaderConfigs()) {
                    initApiParams(processParam, varMap, params, requestHeaderConfig,workflowSchema,processId);
                }
                for (ApiRequestParamsConfig requestBodyConfig : apiConfig.getRequestBodyConfigs()) {
                    initApiParams(processParam, varMap, params, requestBodyConfig,workflowSchema,processId);
                }


                Object result = magicAPIService.execute(info.getMethod(), info.getPath(), params);

                processParam.put(paramAssignmentConfig.getTarget(), result);

            }

        }

    }

    public static void initApiParams(Map<String, Object> processParam, Map<String, Object> varMap, Map<String, Object> params,
                                     ApiRequestParamsConfig requestParamsConfig,WorkflowSchema workflowSchema,String processId) {
        if (Objects.equals(requestParamsConfig.getAssignmentType(), "value")) { //值
            params.put(requestParamsConfig.getName(), requestParamsConfig.getValue());
        } else if (Objects.equals(requestParamsConfig.getAssignmentType(), "processParameter")) { //流程参数
            params.put(requestParamsConfig.getName(), processParam.get(requestParamsConfig.getConfig()));
        } else if (Objects.equals(requestParamsConfig.getAssignmentType(), "originator")) {//发起人信息

            //如果是设置的发起人
            if (requestParamsConfig.getConfig().contains("initiator_id")) {
                Long startUserId = MapUtil.get(varMap, WorkflowConstant.PROCESS_START_USER_ID_KEY, Long.class);

                params.put(requestParamsConfig.getName(), startUserId);
            }
            //组织架构名称
            if (requestParamsConfig.getConfig().contains("initiator_dept_name")) {
                Long startUserId = MapUtil.get(varMap, WorkflowConstant.PROCESS_START_USER_ID_KEY, Long.class);
                RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);
                List<UserDeptRelation> userDeptRelations = redisUtil.get(GlobalConstant.USER_DEPT_RELATION_CACHE_KEY, new TypeReference<List<UserDeptRelation>>() {
                });

                List<Department> departmentList = redisUtil.get(GlobalConstant.DEP_CACHE_KEY, new TypeReference<List<Department>>() {
                });
                List<UserDeptRelation> startUserDeptRelation = userDeptRelations.stream().filter(x -> x.getUserId().equals(startUserId)).collect(Collectors.toList());

                List<Long> allDeptIds = startUserDeptRelation.stream().map(UserDeptRelation::getDeptId).collect(Collectors.toList());

                List<Department> allDept = departmentList.stream().filter(x -> allDeptIds.contains(x.getId())).collect(Collectors.toList());

                params.put(requestParamsConfig.getName(), allDept.stream().map(Department::getName).collect(Collectors.joining(",")));
            }
        } else if (Objects.equals(requestParamsConfig.getAssignmentType(), "data")) {//流程数据
            RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);
            //流程发起人id
            Long startUserId = MapUtil.get(varMap, WorkflowConstant.PROCESS_START_USER_ID_KEY, Long.class);
            //全局流水号
            Long serialNumber = MapUtil.get(varMap, WorkflowConstant.PROCESS_SERIAL_NUMBER_KEY, Long.class);
            //流程发起时间
            LocalDateTime startTime = LocalDateTime.now();
            List<User> uerList = redisUtil.get(GlobalConstant.USER_CACHE_KEY, new TypeReference<List<User>>() {
            });
            User user = uerList.stream().filter(x -> x.getId().equals(startUserId)).findFirst().orElse(new User());

            //获取流程发起时间
            IWorkflowRecordService workflowRecordService = SpringUtil.getBean(IWorkflowRecordService.class);
            List<WorkflowRecord> list = workflowRecordService.list(Wrappers.<WorkflowRecord>lambdaQuery().eq(WorkflowRecord::getProcessId, processId).orderByAsc(WorkflowRecord::getRecordTime));
            if (list.size() > 0){
                startTime = list.get(0).getRecordTime();
            }
            if (requestParamsConfig.getConfig().equals(WorkflowConstant.TEMPLATE_CATEGORY_PLACEHOLDER) && ObjectUtil.isNotNull(workflowSchema.getCategory())){
                List<DictionaryDetail> detailList = redisUtil.get(GlobalConstant.DIC_DETAIL_CACHE_KEY, new TypeReference<List<DictionaryDetail>>() {
                });

                Optional<DictionaryDetail> dictionaryDetail = detailList.stream().filter(x -> x.getId().equals(workflowSchema.getCategory())).findFirst();
                if (dictionaryDetail.isPresent()) {
                    params.put(requestParamsConfig.getName(), dictionaryDetail.get().getName());
                } else {
                    params.put(requestParamsConfig.getName(), workflowSchema.getCategory());
                }
            }
            if (requestParamsConfig.getConfig().equals(WorkflowConstant.TEMPLATE_REMARK_PLACEHOLDER) && StrUtil.isNotBlank(workflowSchema.getRemark())){
                params.put(requestParamsConfig.getName(), workflowSchema.getRemark());
            }
            if (requestParamsConfig.getConfig().equals(WorkflowConstant.TEMPLATE_CODE_PLACEHOLDER) && StrUtil.isNotBlank(workflowSchema.getCode())){
                params.put(requestParamsConfig.getName(), workflowSchema.getCode());
            }
            if (requestParamsConfig.getConfig().equals(WorkflowConstant.TEMPLATE_NAME_PLACEHOLDER) && StrUtil.isNotBlank(workflowSchema.getName())){
                params.put(requestParamsConfig.getName(), workflowSchema.getName());
            }
            if (requestParamsConfig.getConfig().equals(WorkflowConstant.INITIATOR_ID_PLACEHOLDER) && StrUtil.isNotBlank(user.getId().toString())){
                params.put(requestParamsConfig.getName(), user.getId().toString());
            }
            if (requestParamsConfig.getConfig().equals(WorkflowConstant.INITIATOR_USER_NAME_PLACEHOLDER) && StrUtil.isNotBlank(user.getName())){
                params.put(requestParamsConfig.getName(), user.getName());
            }
            if (requestParamsConfig.getConfig().equals(WorkflowConstant.INITIATOR_CODE_PLACEHOLDER) && StrUtil.isNotBlank(user.getCode())){
                params.put(requestParamsConfig.getName(), user.getCode());
            }
            if (requestParamsConfig.getConfig().equals(WorkflowConstant.INITIATOR_MOBILE_PLACEHOLDER) && StrUtil.isNotBlank(user.getMobile())){
                params.put(requestParamsConfig.getName(), user.getMobile());
            }
            if (requestParamsConfig.getConfig().equals(WorkflowConstant.INITIATOR_DEPT_NAME_PLACEHOLDER)){
                List<UserDeptRelation> userDeptRelations = redisUtil.get(GlobalConstant.USER_DEPT_RELATION_CACHE_KEY, new TypeReference<List<UserDeptRelation>>() {
                });
                List<Department> departmentList = redisUtil.get(GlobalConstant.DEP_CACHE_KEY, new TypeReference<List<Department>>() {
                });
                List<UserDeptRelation> startUserDeptRelation = userDeptRelations.stream().filter(x -> x.getUserId().equals(startUserId)).collect(Collectors.toList());

                List<Long> allDeptIds = startUserDeptRelation.stream().map(UserDeptRelation::getDeptId).collect(Collectors.toList());

                List<Department> allDept = departmentList.stream().filter(x -> allDeptIds.contains(x.getId())).collect(Collectors.toList());
                params.put(requestParamsConfig.getName(), allDept.stream().map(Department::getName).collect(Collectors.joining(",")));
            }
            if (requestParamsConfig.getConfig().equals(WorkflowConstant.SERIAL_NUBMER_PLACEHOLDER)){
                params.put(requestParamsConfig.getName(), serialNumber);
            }
            if (requestParamsConfig.getConfig().equals(WorkflowConstant.YYYYMMDDHHMMSS_24_PLACEHOLDER)){
                params.put(requestParamsConfig.getName(), DateUtil.format(startTime, GlobalConstant.YYYY_MM_DD_HH_MM_SS_24));
            }
            if (requestParamsConfig.getConfig().equals(WorkflowConstant.YYYYMMDD_PLACEHOLDER)){
                params.put(requestParamsConfig.getName(), DateUtil.format(startTime, GlobalConstant.YYYY_MM_DD));
            }
            if (requestParamsConfig.getConfig().equals(WorkflowConstant.HHMMSS_24_PLACEHOLDER)){
                params.put(requestParamsConfig.getName(), DateUtil.format(startTime, GlobalConstant.HH_MM_SS_24));
            }
        } else {//表单数据
            //使用3下划线切割
            String[] split = requestParamsConfig.getConfig().split(StringPool.UNDERSCORE + StringPool.UNDERSCORE + StringPool.UNDERSCORE);
            String formKey = split[1];
            Map<String, Object> formData = MapUtil.get(varMap, formKey, new TypeReference<Map<String, Object>>() {
            });
            Object fieldValue = MapUtil.get(formData, split[2], Object.class);
            params.put(requestParamsConfig.getName(), fieldValue);
        }
    }


    /**
     * 根据配置信息 执行表单赋值
     *
     * @param formData         表单数据
     * @param assignmentConfig 赋值配置
     * @param formConfigs      表单配置
     * @param varMap           变量的Map
     */
    public static Map<String, Map<String, Object>> invokeFormAssignment(Map<String, Map<String, Object>> formData, AssignmentConfig assignmentConfig, List<FormConfig> formConfigs, Map<String, Object> varMap) {
        //获取 所有赋值操作数据

        List<FormAssignmentConfig> formAssignmentConfigs = assignmentConfig.getFormAssignmentConfigs();

        for (FormAssignmentConfig formAssignmentConfig : formAssignmentConfigs) {
            Object currentVariable = varMap.get(formAssignmentConfig.getSource());

            FormAssignmentSourceConfig targetSource = formAssignmentConfig.getTarget();

            Optional<FormConfig> formConfig = formConfigs.stream().filter(form -> form.getFormId().toString().equals(targetSource.getFormId().toString())).findFirst();
            formConfig.ifPresent(form -> {
                Map<String, Object> currentFormData = formData.get(form.getKey());

                if (currentFormData.containsKey(targetSource.getFormField())) {
                    currentFormData.put(targetSource.getFormField(), currentVariable);
                    formData.put(form.getKey(),currentFormData);
                }
            });
        }

        //返回表单赋值之后的formData
        return formData;
    }


    /**
     * 判断是否有权限
     *
     * @param authConfig 权限配置
     * @return 是否有权限
     */
    public static Boolean hasPermissions(AuthConfig authConfig) {
        //如果是所有人 默认返回true
        if (authConfig.getAuthType() == WorkflowAuth.ALL.getCode()) {
            return true;
        }
        List<MemberConfig> authMemberConfigs = authConfig.getAuthMemberConfigs();
        SaSession tokenSession = StpUtil.getTokenSession();
        User user = tokenSession.get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());

        //这里可以不传 第二个参数 因为 只有角色岗位人员  用不着childNodeConfig
        List<Long> userIdsByMemberConfig = getUserIdsByMemberConfig(authMemberConfigs, null, null);

        return userIdsByMemberConfig.contains(user.getId());
    }


    /**
     * 获取流程参数
     *
     * @param processParamConfigs
     * @param workflowSchema
     * @return
     */
    @SneakyThrows
    public static Map<String, Object> getProcessParam(List<ProcessParamConfig> processParamConfigs, WorkflowSchema workflowSchema, Long serialNumber,Map<String, Object> varMap) {
        Map<String, Object> result = new HashMap<>(processParamConfigs.size());

        for (ProcessParamConfig processParamConfig : processParamConfigs) {

            //如果是值  直接前端配置  直接传入就行
            if (processParamConfig.getType() == WorkflowParamType.VALUE.getCode()) {
                result.put(processParamConfig.getId(), processParamConfig.getValue());
            }
            //如果是变量
            if (processParamConfig.getType() == WorkflowParamType.VAR.getCode()) {

                String newStr = WorkFlowUtil.replacePlaceHolder(processParamConfig.getValue(), workflowSchema, serialNumber, 0L);

                result.put(processParamConfig.getId(), newStr);
            }


            //如果是api
            if (processParamConfig.getType() == WorkflowParamType.API.getCode()) {

                IMagicApiService magicApiService = SpringUtil.getBean(IMagicApiService.class);
                MagicAPIService magicAPIService = SpringUtil.getBean(MagicAPIService.class);

                ApiConfig apiConfig = processParamConfig.getApiConfig();

                MagicApiInfoVo info = magicApiService.info(processParamConfig.getApiConfig().getId());

                Map<String, Object> params = new HashMap<>();
                for (ApiRequestParamsConfig requestParamsConfig : apiConfig.getRequestParamsConfigs()) {
                    //值
                    if (Objects.equals(requestParamsConfig.getAssignmentType(), "value")) {
                        params.put(requestParamsConfig.getName(), requestParamsConfig.getValue());
                    } else if (Objects.equals(requestParamsConfig.getAssignmentType(),"originator")) {
                        dealApiParam(requestParamsConfig,params,varMap);
                    }
                    //流程数据
                    else {
                        String newStr = WorkFlowUtil.replacePlaceHolder(processParamConfig.getValue(), workflowSchema, serialNumber, 0L);
                        params.put(requestParamsConfig.getName(), newStr);
                    }

                }
                for (ApiRequestParamsConfig requestParamsConfig : apiConfig.getRequestHeaderConfigs()) {
                    //值
                    if (Objects.equals(requestParamsConfig.getDataType(), "value")) {
                        params.put(requestParamsConfig.getName(), requestParamsConfig.getValue());
                    }else if (Objects.equals(requestParamsConfig.getAssignmentType(),"originator")) {
                        dealApiParam(requestParamsConfig,params,varMap);
                    }
                    //流程参数
                    else {
                        String newStr = WorkFlowUtil.replacePlaceHolder(processParamConfig.getValue(), workflowSchema, serialNumber, 0L);
                        params.put(requestParamsConfig.getName(), newStr);
                    }

                }
                for (ApiRequestParamsConfig requestParamsConfig : apiConfig.getRequestBodyConfigs()) {
                    //值
                    if (Objects.equals(requestParamsConfig.getDataType(), "value")) {
                        params.put(requestParamsConfig.getName(), requestParamsConfig.getValue());
                    }else if (Objects.equals(requestParamsConfig.getAssignmentType(),"originator")) {
                        dealApiParam(requestParamsConfig,params,varMap);
                    }
                    //流程参数
                    else {
                        String newStr = WorkFlowUtil.replacePlaceHolder(processParamConfig.getValue(), workflowSchema, serialNumber, 0L);
                        params.put(requestParamsConfig.getName(), newStr);
                    }

                }
                Object execute = magicAPIService.execute(info.getMethod(), info.getPath(), params);
                result.put(processParamConfig.getId(), execute);
            }
        }

        return result;
    }

    private static void dealApiParam(ApiRequestParamsConfig requestParamsConfig, Map<String, Object> params, Map<String, Object> varMap){
        if (CollectionUtils.isEmpty(varMap)){//为空就是发起时的数据
            //如果是拿发起人的数据,作为流程参数,发起和重新发起赋值,使用当前登录人的信息,如果是其它节点,使用流程的发起人数据信息
            SaSession tokenSession = StpUtil.getTokenSession();
            User user = tokenSession.get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());
            //如果是设置的发起人
            if (requestParamsConfig.getConfig().contains("initiator_id")) {
                params.put(requestParamsConfig.getName(), user.getId().toString());
            }
            //组织架构名称
            if (requestParamsConfig.getConfig().contains("initiator_dept_name")) {
                RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);
                List<UserDeptRelation> userDeptRelations = redisUtil.get(GlobalConstant.USER_DEPT_RELATION_CACHE_KEY, new TypeReference<List<UserDeptRelation>>() {
                });

                List<Department> departmentList = redisUtil.get(GlobalConstant.DEP_CACHE_KEY, new TypeReference<List<Department>>() {
                });
                List<UserDeptRelation> startUserDeptRelation = userDeptRelations.stream().filter(x -> x.getUserId().equals(user.getId())).collect(Collectors.toList());

                List<Long> allDeptIds = startUserDeptRelation.stream().map(UserDeptRelation::getDeptId).collect(Collectors.toList());

                List<Department> allDept = departmentList.stream().filter(x -> allDeptIds.contains(x.getId())).collect(Collectors.toList());

                params.put(requestParamsConfig.getName(), allDept.stream().map(Department::getName).collect(Collectors.joining(",")));
            }
        }else {
            //如果是设置的发起人
            if (requestParamsConfig.getConfig().contains("initiator_id")) {
                Long startUserId = MapUtil.get(varMap, WorkflowConstant.PROCESS_START_USER_ID_KEY, Long.class);
                params.put(requestParamsConfig.getName(), startUserId);
            }
            //组织架构名称
            if (requestParamsConfig.getConfig().contains("initiator_dept_name")) {
                Long startUserId = MapUtil.get(varMap, WorkflowConstant.PROCESS_START_USER_ID_KEY, Long.class);
                RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);
                List<UserDeptRelation> userDeptRelations = redisUtil.get(GlobalConstant.USER_DEPT_RELATION_CACHE_KEY, new TypeReference<List<UserDeptRelation>>() {
                });
                List<Department> departmentList = redisUtil.get(GlobalConstant.DEP_CACHE_KEY, new TypeReference<List<Department>>() {
                });
                List<UserDeptRelation> startUserDeptRelation = userDeptRelations.stream().filter(x -> x.getUserId().equals(startUserId)).collect(Collectors.toList());

                List<Long> allDeptIds = startUserDeptRelation.stream().map(UserDeptRelation::getDeptId).collect(Collectors.toList());

                List<Department> allDept = departmentList.stream().filter(x -> allDeptIds.contains(x.getId())).collect(Collectors.toList());

                params.put(requestParamsConfig.getName(), allDept.stream().map(Department::getName).collect(Collectors.joining(",")));
            }
        }
    }

    /**
     * 自定义表单默认使用的就是数据库字段名
     * 而系统表单的表单数据 默认会将 数据库字段转为驼峰命名
     * 所以将formData 的所有key 转为数据库字段名
     * 为了系统表单 所填写 表单数据 能够使用自定义表单接口执行
     *
     * @param forData
     * @return
     */
    public Map<String, Object> conventFormDataKeyToDbField(Map<String, Object> forData) {
        return null;
    }


    /**
     * 清理掉此任务得所有超时提醒
     *
     * @param taskId
     */
    public static void removeTaskTimeoutRemid(String taskId) {
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);
        redisUtil.deleteBatch(WorkflowConstant.TIMEOUT_REMID_KEY + taskId + StringPool.COLON + StringPool.STAR);
    }

    /**
     * 清理掉此流程所有的缓存
     *
     * @param processInstanceId 流程实例id
     */
    public static void removeProcessCache(String processInstanceId) {
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);
        redisUtil.deleteBatch(processInstanceId + StringPool.COLON + StringPool.STAR);
    }

    /**
     * 缓存所有 任务审批人的 记录
     * 格式：
     * {
     * "taskid1" : [userid]                 //普通用户任务节点
     * "taskid2" : [userid,userid,userid]   //会签任务节点（并行）
     * }
     *
     * @param taskId
     */
    public static void cacheTaskAssigneeRecord(String processInstanceId, String taskId, Long userId) {
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);
        if (redisUtil.containsKey(processInstanceId + WorkflowConstant.TASK_ASSIGNEE_RECORD_VAR_KEY)) {
            Map<String, List<Long>> taskAssigneeRecordMap = redisUtil.get(processInstanceId + WorkflowConstant.TASK_ASSIGNEE_RECORD_VAR_KEY, new TypeReference<Map<String, List<Long>>>() {
            });
            List<Long> assigneeUserIds = new ArrayList<>();
            if (taskAssigneeRecordMap.containsKey(taskId)) {
                assigneeUserIds = taskAssigneeRecordMap.get(taskId);
                assigneeUserIds.add(userId);
            } else {
                assigneeUserIds.add(userId);
            }
            taskAssigneeRecordMap.put(taskId, assigneeUserIds);
            redisUtil.set(processInstanceId + WorkflowConstant.TASK_ASSIGNEE_RECORD_VAR_KEY, taskAssigneeRecordMap);
        } else {
            //必须要有序Map
            Map<String, List<Long>> taskAssigneeRecordMap = new LinkedHashMap<>(1);
            List<Long> assigneeUserIds = new ArrayList<>();
            assigneeUserIds.add(StpUtil.getLoginIdAsLong());
            taskAssigneeRecordMap.put(taskId, assigneeUserIds);
            redisUtil.set(processInstanceId + WorkflowConstant.TASK_ASSIGNEE_RECORD_VAR_KEY, taskAssigneeRecordMap);
        }
    }


    /**
     * 根据流程id  和 任务id  获取审批人
     *
     * @param processInstanceId
     * @param taskId
     * @return
     */
    public static List<Long> getTaskAssigneeRecordCache(String processInstanceId, String taskId) {
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);

        Map<String, List<Long>> cache = redisUtil.get(processInstanceId + WorkflowConstant.TASK_ASSIGNEE_RECORD_VAR_KEY, new TypeReference<Map<String, List<Long>>>() {
        });

        return cache.get(taskId);

    }


    /**
     * 缓存任务审批类型 记录
     *
     * @param processInstanceId   流程实例id
     * @param taskId              任务id
     * @param workflowApproveType 审批类型枚举
     */
    public static void cacheTaskApproveType(String processInstanceId, String taskId, Integer workflowApproveType) {
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);
        Map<String, Integer> approveTypeMap;
        if (redisUtil.containsKey(processInstanceId + WorkflowConstant.TASK_APPROVE_TYPE_RECORD_VAR_KEY)) {
            approveTypeMap = redisUtil.get(processInstanceId + WorkflowConstant.TASK_APPROVE_TYPE_RECORD_VAR_KEY, new TypeReference<Map<String, Integer>>() {
            });


        } else {
            approveTypeMap = new HashMap<>(1);
        }
        approveTypeMap.put(taskId, workflowApproveType);
        redisUtil.set(processInstanceId + WorkflowConstant.TASK_APPROVE_TYPE_RECORD_VAR_KEY, approveTypeMap);
    }

    /**
     * 根据参数获取审批类型
     *
     * @param processInstanceId
     * @param taskId
     * @return
     */
    public static Integer getTaskApproveTypeCache(String processInstanceId, String taskId) {
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);
        Map<String, Integer> approveTypeMap = redisUtil.get(processInstanceId + WorkflowConstant.TASK_APPROVE_TYPE_RECORD_VAR_KEY, new TypeReference<Map<String, Integer>>() {
        });

        return approveTypeMap.get(taskId);
    }

    /**
     * 发送传阅人消息提醒(多线程 异步)
     *
     * @param param
     */
    public static void sendCirculatedNoticePolicy(NoticePolicyParam param, String name) {
        //如果有设置通知策略
        if (param.getNoticePolicyConfigs().size() > 0) {

            //如果包含系统消息
            if (param.getNoticePolicyConfigs().contains(WorkflowNoticePolicyType.SYSTEM.getCode())) {
                CompletableFuture.runAsync(() -> {
                    SendMessageUtil.sendWorkflowCirculatedMessage(param);
                });
            }

            //如果包含短信
            if (param.getNoticePolicyConfigs().contains(WorkflowNoticePolicyType.SMS.getCode())) {
                //TODO 发送短信
                CompletableFuture.runAsync(() -> {
                    SendMessageUtil.sendWorkflowCirculatedSms(param, name);
                });
            }
            //如果包含email
            if (param.getNoticePolicyConfigs().contains(WorkflowNoticePolicyType.EMAIL.getCode())) {
                //TODO 发邮件
                CompletableFuture.runAsync(() -> {
                    SendMessageUtil.sendWorkflowCirculatedEmail(param);
                });
            }
            //如果包含企业微信
            if (param.getNoticePolicyConfigs().contains(WorkflowNoticePolicyType.WECHAT.getCode())) {
                //TODO 发送企业微信
                CompletableFuture.runAsync(() -> {
                    SendMessageUtil.sendWorkflowCirculatedWechat(param);
                });
            }
            //如果包含钉钉
            if (param.getNoticePolicyConfigs().contains(WorkflowNoticePolicyType.DING.getCode())) {
                //TODO 发送钉钉
                CompletableFuture.runAsync(() -> {
                    SendMessageUtil.sendWorkflowCirculatedDingtalk(param);
                });
            }

        }
    }

    /**
     * 发送审批人消息提醒(多线程 异步)
     *
     * @param param
     */
    public static void sendApproveNoticePolicy(NoticePolicyParam param, String name) {
        //如果有设置通知策略
        if (param.getNoticePolicyConfigs().size() > 0) {

            //如果包含系统消息
            if (param.getNoticePolicyConfigs().contains(WorkflowNoticePolicyType.SYSTEM.getCode())) {
                CompletableFuture.runAsync(() -> {
                    SendMessageUtil.sendWorkflowApproveMessage(param);
                });
            }

            //如果包含短信
            if (param.getNoticePolicyConfigs().contains(WorkflowNoticePolicyType.SMS.getCode())) {
                //TODO 发送短信
                CompletableFuture.runAsync(() -> {
                    SendMessageUtil.sendWorkflowApproveSms(param, name);
                });
            }
            //如果包含email
            if (param.getNoticePolicyConfigs().contains(WorkflowNoticePolicyType.EMAIL.getCode())) {
                CompletableFuture.runAsync(() -> {
                    SendMessageUtil.sendWorkflowApproveEmail(param);
                });
            }
            //如果包含企业微信
            if (param.getNoticePolicyConfigs().contains(WorkflowNoticePolicyType.WECHAT.getCode())) {
                //TODO 发送企业微信

                CompletableFuture.runAsync(() -> {
                    SendMessageUtil.sendWorkflowApproveWechat(param);
                });
            }
            //如果包含钉钉
            if (param.getNoticePolicyConfigs().contains(WorkflowNoticePolicyType.DING.getCode())) {
                //TODO 发送钉钉
                CompletableFuture.runAsync(() -> {
                    SendMessageUtil.sendWorkflowApproveDingtalk(param);
                });
            }

        }
    }

    /**
     * 发送审批人流程任务催办信息(多线程 异步)
     *
     * @param
     */
    public static void sendApproveUrge(List<WorkflowExtra> workflowExtras, String urgeType) {
        //0-系统消息，1-短信，默认为系统消息
        if (urgeType.contains("0")){
            CompletableFuture.runAsync(() -> {
                SendMessageUtil.sendWorkflowUrgeMessage(workflowExtras);
            });
        }
        if(urgeType.contains("1")) {
            CompletableFuture.runAsync(() -> {
                SendMessageUtil.sendWorkflowUrgeSms(workflowExtras);
            });
        }
    }

    /**
     * 发送超时消息提醒(多线程 异步)
     *
     * @param param
     */
    public static void sendTimeOutNoticePolicy(NoticePolicyParam param, String name) {
        //如果有设置通知策略
        if (param.getNoticePolicyConfigs().size() > 0) {

            //如果包含系统消息
            if (param.getNoticePolicyConfigs().contains(WorkflowNoticePolicyType.SYSTEM.getCode())) {
                CompletableFuture.runAsync(() -> {
                    SendMessageUtil.sendWorkflowTimeoutMessage(param);
                });
            }

            //如果包含短信
            if (param.getNoticePolicyConfigs().contains(WorkflowNoticePolicyType.SMS.getCode())) {
                //TODO 发送短信
                CompletableFuture.runAsync(() -> {
                    SendMessageUtil.sendWorkflowTimeoutSms(param, name);
                });
            }
            //如果包含email
            if (param.getNoticePolicyConfigs().contains(WorkflowNoticePolicyType.EMAIL.getCode())) {
                CompletableFuture.runAsync(() -> {
                    SendMessageUtil.sendWorkflowTimeoutEmail(param);
                });
            }
            //如果包含企业微信
            if (param.getNoticePolicyConfigs().contains(WorkflowNoticePolicyType.WECHAT.getCode())) {
                //TODO 发送企业微信
                CompletableFuture.runAsync(() -> {
                    SendMessageUtil.sendWorkflowTimeoutWechat(param);
                });
            }
            //如果包含钉钉
            if (param.getNoticePolicyConfigs().contains(WorkflowNoticePolicyType.DING.getCode())) {
                //TODO 发送钉钉
                CompletableFuture.runAsync(() -> {
                    SendMessageUtil.sendWorkflowTimeoutDingtalk(param);
                });
            }

        }
    }

    /**
     * 根据用户id获取对应的用户名，并进行拼接输出
     *
     * @param allUserIds 用户ids
     * @return 用户名（张三、李四）
     */
    public static String getAllUserNamesByIds(List<Long> allUserIds) {

        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);
        String allDelegateUserNames = StringPool.EMPTY;
        List<User> userList = redisUtil.get(GlobalConstant.USER_CACHE_KEY, new TypeReference<List<User>>() {
        });
        //如果缓存中不存在用户信息，就直接去数据库查询,并保存到缓存中去
        if (userList.size() == 0) {
            IUserService userService = SpringUtil.getBean(IUserService.class);
            userList = userService.list();
            redisUtil.set(GlobalConstant.USER_CACHE_KEY, userList);
        }
        if (allUserIds.size() > 0) {
            //获取用户id对应的用户名
            List<String> allUserName = userList.stream().filter(u -> allUserIds.contains(u.getId())).map(User::getName).collect(Collectors.toList());
            String chineseDot = "、";

            if (allUserName.size() > 0) {
                allDelegateUserNames = StrUtil.join(chineseDot, allUserName);
            }
        }
        return allDelegateUserNames;
    }

    /**
     * 发起流程时， 遍历所有节点 如果有需要监听器的  默认缓存 key -> deployId:ActivityId
     *
     * @param deployId        部署id
     * @param childNodeConfig 所有节点配置
     */
    public static void cacheNodeListener(String deployId, List<Map<String, Object>> childNodeConfig) {
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);
        for (Map<String, Object> map : childNodeConfig) {
            //转换为node 配置类型
            NodeBasicConfig nodeBasicConfig = BeanUtil.toBean(map, NodeBasicConfig.class);

            if (nodeBasicConfig.getStartEventConfigs().size() > 0) {
                String startKey = WorkflowConstant.START_EVENT_CACHE_PRE + deployId + StringPool.COLON + nodeBasicConfig.getId() + StringPool.COLON + WorkflowEventType.START.getValue();
                redisUtil.set(startKey, nodeBasicConfig.getStartEventConfigs());
            }
            if (nodeBasicConfig.getEndEventConfigs().size() > 0) {
                String endKey = WorkflowConstant.END_EVENT_CACHE_PRE + deployId + StringPool.COLON + nodeBasicConfig.getId() + StringPool.COLON + WorkflowEventType.END.getValue();
                redisUtil.set(endKey, nodeBasicConfig.getEndEventConfigs());
            }


        }
    }

    /**
     * 删除监听器
     *
     * @param deployId 部署id
     */
    public static void removeNodeListener(String deployId) {
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);

        redisUtil.deleteBatch(deployId + StringPool.COLON + "*");
    }

    /**
     * 获取一天的开始时间 00:00:00
     *
     * @param date 某一天时间
     * @return 某一天的开始时间, 比如2023-01-01 00:00:00
     */
    public static Date getStartOfDay(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    /**
     * 获取一天的结束时间 23:59:59
     *
     * @param date 某一天时间
     * @return 某一天的结束时间, 比如2023-01-01 23:59:59
     */
    public static Date getEndOfDay(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return calendar.getTime();
    }

    /**
     * 发送消息推送公用方法
     * @param configList 参数配置信息
     * @param receiverConfigurationList 接收人员配置信息
     * @param id 消息模板id
     * @return
     */
    public static Boolean sendMessageCommon(Long id,List<MessageAssignmentConfig> configList,List<ReceiverConfiguration> receiverConfigurationList,
                                            Map<String, Object> varMap,List<Map<String, Object>> childNodeConfig, String processId,Long formId){
        //根据id获取对应的消息模板配置信息
        IMessageTemplateService messageTemplateService = SpringUtil.getBean(IMessageTemplateService.class);
        MessageTemplate messageTemplate = messageTemplateService.getById(id);
        if (messageTemplate == null){
            throw new MyException("选择的消息模板不存在");
        }
        //获取消息模板内容的配置
        MessageTemplateConfig messageTemplateConfig = JSONUtil.toBean(messageTemplate.getMessageConfig(), MessageTemplateConfig.class);

        //获取消息内容
        MessageContent messageContent = messageTemplateConfig.getMessageContent();
        if (messageContent == null){
            throw new MyException("所选的消息模板消息内容配置为空");
        }
        //获取参数配置
        List<ConfigureData> configureDataList = messageTemplateConfig.getConfigureData();

        if (messageTemplate.getMessageType() == SystemConfigEnum.EMAIL.getCode()
                || messageTemplate.getMessageType() == SystemConfigEnum.SYSTEM_MESSAGE.getCode()
                || messageTemplate.getMessageType() == SystemConfigEnum.DINGTALK.getCode()
                || messageTemplate.getMessageType() == SystemConfigEnum.WECHAT.getCode()
                || messageTemplate.getMessageType() == SystemConfigEnum.WEBHOOK.getCode()){

            if (StringUtils.isBlank(messageContent.getContent())){
                throw new MyException("所选系统消息模板的消息内容为空");
            }
            //对消息内容参数进操作,是否包含{}
            String content = messageContent.getContent();
            if (messageContent.getContent().contains("{") && messageContent.getContent().contains("}")) {//包含，则对变量进行替换，不包含直接发送消息
                if (configureDataList.size() == 0){
                    throw new MyException("相应消息模板未进行参数配置，无法进行变量匹配");
                }else {
                    content = ReplaceContent(content,configureDataList,configList,varMap);
                }
            }
            //获取需要进行消息推送的人员名单
            List<Long> messagePushUserIds = getMessagePushUserIds(receiverConfigurationList, childNodeConfig, processId, formId);
            if (messagePushUserIds.size() > 0){
                if (messageTemplate.getMessageType() == SystemConfigEnum.EMAIL.getCode()){// 发送邮件信息
                    String title= messageContent.getTitle();//获取标题
                    SendMessageUtil.sendEmailMessageCommon(messagePushUserIds,content,title);
                }
                if (messageTemplate.getMessageType() == SystemConfigEnum.SYSTEM_MESSAGE.getCode()){//发送系统消息
                    SendMessageUtil.sendSystemMessageCommon(messagePushUserIds,content,formId);
                }
                if (messageTemplate.getMessageType() == SystemConfigEnum.WECHAT.getCode()) {// 发送企业微信消息
                    String title= messageContent.getTitle();//获取标题
                    SendMessageUtil.sendWeChatMessageCommon(messagePushUserIds,content,title);
                }
                if (messageTemplate.getMessageType() == SystemConfigEnum.DINGTALK.getCode()) {//发送钉钉消息
                    String title= messageContent.getTitle();//获取标题
                    SendMessageUtil.sendDingtalkMessageCommon(messagePushUserIds,content,title);
                }
                if (messageTemplate.getMessageType() == SystemConfigEnum.WEBHOOK.getCode()){// 页面钩子
                    String title= messageContent.getTitle();//获取标题
                    SendMessageUtil.sendWebhookMessageCommon(messagePushUserIds,content,title);
                }
            }

        }else if (messageTemplate.getMessageType() == SystemConfigEnum.WECHAT_OFFICIAL.getCode()) { //微信公众号
            //消息内容里面的变量配置
            List<MessageVariable> configs = messageContent.getConfigs();
            if (configureDataList.size() == 0){
                throw new MyException("相应消息模板未进行参数配置，无法进行变量匹配");
            }else {
                //获取微信公众号消息模板数据
                LinkedHashMap<String, String> mapData = getVariableValue(configs,configureDataList,configList,varMap);
                //构建数据
                TreeMap<String, TreeMap<String, String>> data = new TreeMap<>();
                if (mapData.size() > 0){
                    Set<String> strings = mapData.keySet();
                    for (String key : strings) {
                        //变量key值
                        String value = mapData.get(key);
                        TreeMap<String, String> params = new TreeMap<String, String>();
                        //变量value值
                        params.put("value", value);
                        //变量颜色，默认为黑色
                        params.put("color", "#000000");
                        data.put(key,params);
                    }
                }
                //获取需要进行消息推送的人员名单
                List<Long> messagePushUserIds = getMessagePushUserIds(receiverConfigurationList, childNodeConfig, processId, formId);
                SendMessageUtil.sendWechatOfficialMessageCommon(messagePushUserIds,data,messageContent);
            }
        }else if (messageTemplate.getMessageType() == SystemConfigEnum.MESSAGE.getCode()) { //短信
            //消息内容里面的变量配置
            List<MessageVariable> configs = messageContent.getConfigs();
            if (configureDataList.size() == 0){
                throw new MyException("相应消息模板未进行参数配置，无法进行变量匹配");
            }else {
                //获取短信消息模板数据
                LinkedHashMap<String, String> data = getVariableValue(configs,configureDataList,configList,varMap);
                //获取需要进行消息推送的人员名单
                List<Long> messagePushUserIds = getMessagePushUserIds(receiverConfigurationList, childNodeConfig, processId, formId);
                //获取模板编号
                String templateId = messageContent.getTemplateCode();
                SendMessageUtil.sendShortMessageCommon(messagePushUserIds,templateId,data);
            }
        }
        return true;
    }

    /**
     * 对变量进行替换的方法
     * @param content 消息内容
     * @param configureDataList 参数配置列表集合
     * @param configList 消息推送参数来源集合
     * @return
     */
    public static String ReplaceContent(String content,List<ConfigureData> configureDataList,List<MessageAssignmentConfig> configList,Map<String, Object> varMap){

        //找到字符串中第一个左括号的位置
        int leftIndex = content.indexOf("{");
        if (leftIndex == -1){//不存在左括号，则不需要替换，直接返回
            return content;
        }
        //找到左括号后的第一个右括号的位置
        int rightIndex = content.indexOf("}", leftIndex);
        if (rightIndex == -1){
            throw new MyException("请检查消息模板的消息内容是否缺失一个"+"}");
        }
        while (leftIndex != -1 && rightIndex != -1){
            //获取消息内容里面的变量名称
            String variableName = content.substring(leftIndex + 1,rightIndex);
            String newVariableName = StringPool.EMPTY;
            //去参数配置里面找对应的变量信息
            Optional<ConfigureData> first = configureDataList.stream().filter(x -> StrUtil.isNotBlank(x.getName()) && x.getName().equals(variableName)).findFirst();
            if (!first.isPresent()) {
                throw new MyException(variableName+"找不到对应的消息模板参数配置");
            }
            ConfigureData configureData = first.get();
            Optional<MessageAssignmentConfig> messageAssignmentConfigFirst = configList.stream().filter(x -> StrUtil.isNotBlank(x.getName()) && x.getName().equals(configureData.getName())).findFirst();
            if (!messageAssignmentConfigFirst.isPresent()) {
                throw new MyException(variableName+"找不到对应的参数配置");
            }
            MessageAssignmentConfig messageAssignmentConfig = messageAssignmentConfigFirst.get();
            if (messageAssignmentConfig.getAssignmentType().equals("formData")){//表单数据
                if (varMap != null){
                    //工作流，格式：Event_start_node___form_1744643242619990018_1706079050514___dan_xing_wen_ben4700，获取开始节点，的表单的对应字段的值
                    //使用3下划线切割
                    String[] split = messageAssignmentConfig.getConfig().split(StringPool.UNDERSCORE + StringPool.UNDERSCORE + StringPool.UNDERSCORE);
                    String formKey = split[1];
                    Map<String, Object> formData = MapUtil.get(varMap, formKey, new TypeReference<Map<String, Object>>() {
                    });
                    Object fieldValue = MapUtil.get(formData, split[2], Object.class);
                    newVariableName = fieldValue.toString();

                }else {
                    //代码生成器，获取表单对应的字段值
                    newVariableName = messageAssignmentConfig.getValue();
                }
            }else{//值
                newVariableName = messageAssignmentConfig.getValue();
            }
            //重新组合内容
            content = content.substring(0,leftIndex) + newVariableName + content.substring(rightIndex+1);

            //组合完之后，继续找下一个括号的位置
            leftIndex = content.indexOf("{",leftIndex);
            rightIndex = content.indexOf("}",leftIndex);
        }
        return content;
    }

    /**
     * 获取推送人员，因为不仅仅是工作流使用、还有表单事件-用户自定义节点也要使用，MemberType与工作流那边有区别，所以另外写一个方法
     * @param receiverConfigurationList
     * @return
     */
    public static List<Long> getMessagePushUserIds(List<ReceiverConfiguration> receiverConfigurationList,List<Map<String, Object>> childNodeConfig, String processId,Long formId){
        List<Long> result = new ArrayList<>();
        if (receiverConfigurationList.size() == 0) {
            return result;
        }
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);
        //如果有选择角色
        List<UserRoleRelation> userRoleRelations = null;
        List<UserPostRelation> userPostRelations = null;

        for (ReceiverConfiguration receiverConfiguration : receiverConfigurationList) {
            //用户直接把用户id加入集合中
            if(receiverConfiguration.getMemberType() == FromMemberType.USER.getCode()){
                result.add(Convert.toLong(receiverConfiguration.getId()));
            }
            // 根据所有角色id   从 缓存中获取 所有 用户角色关联信息
            // 获取到所有用户id  添加到返回值中
            if(receiverConfiguration.getMemberType() == FromMemberType.ROLE.getCode()){//角色
                if (ObjectUtil.isNull(userRoleRelations)) {
                    // 从 缓存中获取到所有角色数据
                    userRoleRelations = redisUtil.get(GlobalConstant.USER_ROLE_RELATION_CACHE_KEY, new TypeReference<List<UserRoleRelation>>() {
                    });
                }
                //获取到所有角色的关联用户
                List<Long> userIds = userRoleRelations.stream().filter(x -> x.getRoleId().equals(Convert.toLong(receiverConfiguration.getId()))).map(UserRoleRelation::getUserId).collect(Collectors.toList());
                result.addAll(userIds);
            }
            //从缓存中获取岗位下的人员ids
            if (receiverConfiguration.getMemberType() == FromMemberType.POST.getCode()){
                if (ObjectUtil.isNull(userPostRelations)) {
                    //从缓存中获取所有的用户与岗位关联信息
                    userPostRelations = redisUtil.get(GlobalConstant.USER_POST_RELATION_CACHE_KEY, new TypeReference<List<UserPostRelation>>() {
                    });
                }
                //进行过滤，将对应岗位下的人员进行获取
                List<Long> userIds = userPostRelations.stream().filter(p -> ObjectUtil.equals(Convert.toLong(receiverConfiguration.getId()), p.getPostId())).map(UserPostRelation::getUserId).collect(Collectors.toList());
                result.addAll(userIds);
            }
            if (receiverConfiguration.getMemberType() == FromMemberType.SPECIFY_NODE_APPROVE.getCode()){//指定节点审批人,只有工作流有这个操作
                getApproveUserIdsByNodeId(result,receiverConfiguration.getId(),processId,childNodeConfig);
            }
            if (receiverConfiguration.getMemberType() == FromMemberType.FORM_FIELD.getCode()){//表单字段，又分为工作流表单字段和表单字段
                if (StrUtil.isNotBlank(processId)){
                    //将map 转为 java类  默认只有用户任务节点才有审批人
                    RuntimeService runtimeService = ProcessEngines.getDefaultProcessEngine().getRuntimeService();

                    FormFieldConfig formFieldConfigs = receiverConfiguration.getFormFieldConfig();

                    Object formDataObj = runtimeService.getVariable(processId, formFieldConfigs.getFormKey());
                    Map<String, Object> formData = Convert.toMap(String.class, Object.class, formDataObj);

                    Object fieldValue = formData.get(formFieldConfigs.getFormField());

                    //将审批的值插入到审批人result中
                    buildApproveIdResult(fieldValue,result);
                }else {
                    receiverConfiguration.getValue();
                    //将审批的值插入到审批人result中
                    buildApproveIdResult(receiverConfiguration.getValue(),result);
                }
            }
            if (receiverConfiguration.getMemberType() == FromMemberType.CURRENT_NODE_CANDIDATE.getCode()){//工作流：当前节点候选审批人
                getApproveUserIdsByNodeId(result,receiverConfiguration.getId(),processId,childNodeConfig);
            }
            if (receiverConfiguration.getMemberType() == FromMemberType.FORM_CREATOR.getCode()){//表单，表单创建人
                if (ObjectUtil.isNotNull(formId)){
                    //根据表单id获取表单创建人
                    IFormTemplateService formTemplateService = SpringUtil.getBean(IFormTemplateService.class);
                    FormTemplate formTemplate = formTemplateService.getById(formId);
                    if (formTemplate !=null && ObjectUtil.isNotEmpty(formTemplate.getCreateUserId())){
                        result.add(formTemplate.getCreateUserId());
                    }
                }
            }
        }
        return result;
    }

    /**
     * 根据节点id获取审批人
     * @return
     */
    public static void getApproveUserIdsByNodeId(List<Long> result,String nodeId,String processId,List<Map<String, Object>> childNodeConfig){
        //如果是选择的开始节点，就把开始节点的审批人加进来
        if (nodeId.equals(WorkflowConstant.START_NODE_DEFAULT_ID)) {
            //将map 转为 java类  默认只有用户任务节点才有审批人
            RuntimeService runtimeService = ProcessEngines.getDefaultProcessEngine().getRuntimeService();

            Object startUserIdObj = runtimeService.getVariable(processId, WorkflowConstant.PROCESS_START_USER_ID_KEY);
            Long startUserId = Convert.toLong(startUserIdObj);
            result.add(startUserId);
            return;
        }

        //必须是用户任务节点
        Optional<Map<String, Object>> userTaskConfigMapOp = childNodeConfig.stream().filter(x -> x.containsValue(nodeId)).findFirst();
        if (!userTaskConfigMapOp.isPresent()) {
            return;
        }
        //    将map 转为 java类
        UserTaskConfig userTaskConfig = Convert.convert(UserTaskConfig.class, userTaskConfigMapOp.get());
        List<Long> approverUserIds = getUserIdsByMemberConfig(userTaskConfig.getApproverConfigs(), childNodeConfig, processId);
        result.addAll(approverUserIds);
    }


    /**
     *
     * @param configs 消息模板-消息内容配置-参数与变量配置信息
     * @param configureDataList 消息模板-参数配置
     * @param configList 工作流或者表单配置的参数赋值信息
     * @param varMap 工作流数据集合
     * @return
     */
    public static LinkedHashMap<String, String> getVariableValue(List<MessageVariable> configs, List<ConfigureData> configureDataList,List<MessageAssignmentConfig> configList,Map<String, Object> varMap){
        LinkedHashMap<String, String> data = new LinkedHashMap<>();
        //进行变量赋值
        if (configs.size() == 0){
            throw new MyException("相应消息模板未进行变量配置，无法进行变量匹配");
        }
        for (MessageVariable config : configs) {//循环变量配置信息
            //对所选参数进行赋值操作
            //去参数配置里面找对应的变量信息
            Optional<ConfigureData> first = configureDataList.stream().filter(x -> StrUtil.isNotBlank(x.getName()) && x.getName().equals(config.getParameter())).findFirst();
            if (!first.isPresent()) {
                throw new MyException(config.getParameter()+"找不到对应的消息模板参数配置");
            }
            ConfigureData configureData = first.get();
            Optional<MessageAssignmentConfig> messageAssignmentConfigFirst = configList.stream().filter(x -> StrUtil.isNotBlank(x.getName()) && x.getName().equals(configureData.getName())).findFirst();
            if (!messageAssignmentConfigFirst.isPresent()) {
                throw new MyException(config.getParameter()+"找不到对应的参数配置");
            }
            MessageAssignmentConfig messageAssignmentConfig = messageAssignmentConfigFirst.get();
            if (messageAssignmentConfig.getAssignmentType().equals("formData")){//表单数据
                if (varMap != null){
                    //工作流，格式：Event_start_node___form_1744643242619990018_1706079050514___dan_xing_wen_ben4700，获取开始节点，的表单的对应字段的值
                    //使用3下划线切割
                    String[] split = messageAssignmentConfig.getConfig().split(StringPool.UNDERSCORE + StringPool.UNDERSCORE + StringPool.UNDERSCORE);
                    String formKey = split[1];
                    Map<String, Object> formData = MapUtil.get(varMap, formKey, new TypeReference<Map<String, Object>>() {
                    });
                    Object fieldValue = MapUtil.get(formData, split[2], Object.class);
                    //config.getVariable(),作为key值，与微信公众号的变量key值一致，fieldValue作为值
                    data.put(config.getVariable(),fieldValue.toString());
                }else {
                    //代码生成器，获取表单对应的字段值
                    data.put(config.getVariable(),messageAssignmentConfig.getValue());
                }
            }else{//值
                data.put(config.getVariable(),messageAssignmentConfig.getValue());
            }
        }
        return data;
    }

    /**
     * 构建摘要信息
     * @param summaryInfoList 摘要信息集合
     * @param varMap 流程保存的数据集合
     */
    public static String buildSummaryInfo(List<SummaryInfo> summaryInfoList,Map<String, Object> varMap){
        List<String> summaryInfoValueList = new ArrayList<>();
        String summaryInfoValue = StringPool.EMPTY;
        for (SummaryInfo summaryInfo : summaryInfoList) {
            RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);
            if (summaryInfo.getFormKey().contains("form_")){ //如果key中包含form_,则说明是表单字段,则需要获取流程里面表单的formData进行比对,存在就赋值，不存在就显示空
                Map<String, Object> formData = MapUtil.get(varMap, summaryInfo.getFormKey(), new TypeReference<Map<String, Object>>() {
                });
                String fieldValue = StringPool.EMPTY;
                if (ObjectUtil.isNotEmpty(formData) && formData.containsKey(summaryInfo.getFieldId())){
                    fieldValue = MapUtil.get(formData, summaryInfo.getFieldId(), Object.class).toString();
                }
                if (ObjectUtil.isNotEmpty(formData)){
                    if (formData.containsKey(summaryInfo.getFieldId())){
                        fieldValue = MapUtil.get(formData, summaryInfo.getFieldId(), Object.class).toString();
                    }else {//转驼峰,获取值
                        final Set<String> formDataKeySet = formData.keySet();
                        Map<String, Object> formDataNew = new HashMap<>();
                        for (String key : formDataKeySet) {
                            StringUtils.underlineToCamel(key);
                            Object o = formData.get(key);
                            formDataNew.put(StringUtils.underlineToCamel(key),o);
                        }
                        if (formDataNew.containsKey(summaryInfo.getFieldId())){
                            fieldValue = MapUtil.get(formDataNew, summaryInfo.getFieldId(), Object.class).toString();
                        }
                    }
                }
                //获取对应的字段值
                fieldValue = getFiledValue(summaryInfo,fieldValue);
                //字段名称：字段值，
                summaryInfoValueList.add(summaryInfo.getFieldName() + StringPool.COLON + fieldValue);
            }else {//发起人名称等字段
                if (summaryInfo.getFieldId().equals("name")){//发起人名称
                    String startUserName = MapUtil.get(varMap, WorkflowConstant.PROCESS_START_USER_NAME_KEY, String.class);
                    //发起人名称：张三，
                    summaryInfoValueList.add(summaryInfo.getFieldName() + StringPool.COLON + startUserName);
                } else if (summaryInfo.getFieldId().equals("deptName") || summaryInfo.getFieldId().equals("companyName")) {//发起人所属部门名称、公司名称，暂时未作区分
                    //先获取发起时所属的岗位
                    Long startUserPostIdKey = MapUtil.get(varMap, WorkflowConstant.PROCESS_START_USER_POST_ID_KEY, Long.class);
                    //再拿岗位去获取属于那个部门
                    List<Post> postList = redisUtil.get(GlobalConstant.POST_CACHE_KEY, new TypeReference<List<Post>>() {
                    });
                    Post post = postList.stream().filter(x -> x.getId().equals(startUserPostIdKey)).findFirst().orElse(new Post());
                    String deptName = StringPool.EMPTY;
                    if (ObjectUtil.isNotEmpty(post.getDeptId())){
                        Long deptId = post.getDeptId();
                        List<Department> departmentList = redisUtil.get(GlobalConstant.DEP_CACHE_KEY, new TypeReference<List<Department>>() {
                        });
                        Department department = departmentList.stream().filter(x -> x.getId().equals(deptId)).findFirst().orElse(new Department());
                        deptName = department.getName();
                    }
                    //部门名称：开发部，
                    summaryInfoValueList.add(summaryInfo.getFieldName() + StringPool.COLON + deptName);
                } else if (summaryInfo.getFieldId().equals("postName")) {
                    //先获取发起时所属的岗位
                    Long startUserPostIdKey = MapUtil.get(varMap, WorkflowConstant.PROCESS_START_USER_POST_ID_KEY, Long.class);
                    //再拿岗位去获取属于那个部门
                    List<Post> postList = redisUtil.get(GlobalConstant.POST_CACHE_KEY, new TypeReference<List<Post>>() {
                    });
                    Post post = postList.stream().filter(x -> x.getId().equals(startUserPostIdKey)).findFirst().orElse(new Post());
                    String postName = StringPool.EMPTY;
                    if (StrUtil.isNotBlank(post.getName())){
                        postName = post.getName();
                    }
                    //岗位名称：后端开发工程师，
                    summaryInfoValueList.add(summaryInfo.getFieldName() + StringPool.COLON + postName);
                }else if (summaryInfo.getFieldId().equals("roleName")) {
                    //先获取发起人id
                    Long startUserIdKey = MapUtil.get(varMap, WorkflowConstant.PROCESS_START_USER_ID_KEY, Long.class);
                    //再拿用户id获取用户角色信息
                    List<UserRoleRelation> userRoleRelationList = redisUtil.get(GlobalConstant.USER_ROLE_RELATION_CACHE_KEY, new TypeReference<List<UserRoleRelation>>() {
                    });
                    //用户所属角色
                    List<Long> roleIds = userRoleRelationList.stream().filter(x -> x.getUserId().equals(startUserIdKey)).map(UserRoleRelation::getRoleId).collect(Collectors.toList());
                    String roleName = StringPool.EMPTY;
                    if (roleIds.size() > 0){
                        List<Role> roleList = redisUtil.get(GlobalConstant.ROLE_CACHE_KEY, new TypeReference<List<Role>>() {
                        });
                        List<String> nameList = roleList.stream().filter(x -> roleIds.contains(x.getId())).map(Role::getName).collect(Collectors.toList());
                        roleName = StrUtil.join("、",nameList);
                    }
                    summaryInfoValueList.add(summaryInfo.getFieldName() + StringPool.COLON + roleName);
                } else if (summaryInfo.getFieldId().equals("templateName")) {
                    String templateName = MapUtil.get(varMap, WorkflowConstant.PROCESS_SCHEMA_NAME_KEY, String.class);
                    //流程模板名称：xxx
                    summaryInfoValueList.add(summaryInfo.getFieldName() + StringPool.COLON + templateName);
                } else if (summaryInfo.getFieldId().equals("templateCategory")) {
                    //模板id
                    Long schemaId = MapUtil.get(varMap, WorkflowConstant.PROCESS_SCHEMA_ID_KEY, Long.class);
                    IWorkflowSchemaService workflowSchemaService = SpringUtil.getBean(IWorkflowSchemaService.class);
                    WorkflowSchema workflowSchema = workflowSchemaService.getOne(Wrappers.lambdaQuery(WorkflowSchema.class).eq(WorkflowSchema::getId, schemaId));
                    List<DictionaryDetail> detailList = redisUtil.get(GlobalConstant.DIC_DETAIL_CACHE_KEY, new TypeReference<List<DictionaryDetail>>() {
                    });

                    Optional<DictionaryDetail> dictionaryDetail = detailList.stream().filter(x -> x.getId().equals(workflowSchema.getCategory())).findFirst();

                    String templateCategoryName = StringPool.EMPTY;
                    if (dictionaryDetail.isPresent()) {
                        templateCategoryName = StrUtil.toString(dictionaryDetail.get().getName());
                    } else {
                        templateCategoryName = StrUtil.toString(workflowSchema.getCategory());
                    }
                    //流程模板分类:xxx
                    summaryInfoValueList.add(summaryInfo.getFieldName() + StringPool.COLON + templateCategoryName);
                } else if (summaryInfo.getFieldId().equals("startTimeHH")) {
                    //流程发起时间(yyyy-MM-dd HH:mm:ss)
                    summaryInfoValueList.add(summaryInfo.getFieldName() + StringPool.COLON + DateUtil.format(LocalDateTime.now(), GlobalConstant.YYYY_MM_DD_HH_MM_SS_24));
                } else if (summaryInfo.getFieldId().equals("startTime")) {
                    //流程发起时间(yyyy-MM-dd)
                    summaryInfoValueList.add(summaryInfo.getFieldName() + StringPool.COLON + DateUtil.format(LocalDateTime.now(), GlobalConstant.YYYY_MM_DD));
                }
            }
        }
        if (summaryInfoValueList.size() > 0){
            //将值用，隔开
            summaryInfoValue = StrUtil.join(StringPool.COMMA,summaryInfoValueList);
        }
        return summaryInfoValue;
    }

    /**
     * 获取对应的字段值
     * @param summaryInfo
     * @param fieldValue
     * @return
     */
    private static String getFiledValue(SummaryInfo summaryInfo,String fieldValue){
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);;
        //如果是用户、数据字典、api数据、部门、岗位、行政区域、级联等字段，需要进行数据转换再进行保存
        //获取到表单id
        String[] split = summaryInfo.getFormKey().split(StringPool.UNDERSCORE);
        Long formId = Convert.toLong(split[1]);
        IFormTemplateService formTemplateService = SpringUtil.getBean(IFormTemplateService.class);
        FormTemplate formTemplate = formTemplateService.getById(formId);
        String formJson = formTemplate.getFormJson();
        //自定义表单配置
        FormDesignConfig formDesignConfig = JSONUtil.toBean(formJson, FormDesignConfig.class);
        //表关系配置
        List<TableConfig> tableConfigs = formDesignConfig.getTableConfigs();
        //主表
        Optional<TableConfig> mainTable = tableConfigs.stream().filter(TableConfig::getIsMain).findFirst();
        if (mainTable.isPresent()) {
            String tableName = mainTable.get().getTableName();
            //获取主表配置
            Map<String, List<ComponentConfig>> componentListMap = GeneratorUtil.buildFormComponentList(formDesignConfig.getFormJson().getList());
            List<ComponentConfig> configList = componentListMap.get(tableName);
            Optional<ComponentConfig> first = configList.stream().filter(x -> StrUtil.isNotBlank(x.getBindField())
                    && (x.getBindField().equals(summaryInfo.getFieldId())
                    || StringUtils.underlineToCamel(x.getBindField()).equals(summaryInfo.getFieldId()))).findFirst();
            StringBuilder tranValue = new StringBuilder();
            if (first.isPresent()) {
                //当前字段的类型，看是不是用户、数据字典、api数据、部门、岗位、行政区域、级联等字段
                ComponentConfig componentConfig = first.get();
                String componentType = componentConfig.getType();
                Map<String, Object> options = componentConfig.getOptions();
                Integer infoType = MapUtils.getInteger(options, "infoType");
                if (StrUtil.equalsIgnoreCase(componentType, ComponentTypeConstant.INFO)
                        || StrUtil.equalsIgnoreCase(componentType,ComponentTypeConstant.USER)
                        || StrUtil.equalsIgnoreCase(componentType,ComponentTypeConstant.ORGANIZATION)) {
                    if ((ObjectUtil.isNotEmpty(infoType) && infoType == 0)|| StrUtil.equalsIgnoreCase(componentType,ComponentTypeConstant.USER)) {
                        //用户
                        List<User> userList = redisUtil.get(GlobalConstant.USER_CACHE_KEY, new TypeReference<List<User>>() {
                        });
                        List<String> idList = StrUtil.split(fieldValue.toString(), StringPool.COMMA);
                        if (idList.size() > 0) {
                            for (String id : idList) {
                                final Long userId = Convert.toLong(id);
                                Optional<User> userOptional = userList.stream().filter(x -> x.getId().equals(userId)).findFirst();
                                if (userOptional.isPresent()) {
                                    User user = userOptional.get();
                                    if (tranValue.length() > 0) {
                                        tranValue.append(StringPool.COMMA);
                                    }
                                    tranValue.append(user.getName());
                                }
                            }
                            fieldValue = tranValue.toString();
                        }
                        return fieldValue;
                    } else if ((ObjectUtil.isNotEmpty(infoType) && infoType == 1) || StrUtil.equalsIgnoreCase(componentType,ComponentTypeConstant.ORGANIZATION)) {
                        //组织
                        List<Department> departmentList = redisUtil.get(GlobalConstant.DEP_CACHE_KEY, new TypeReference<List<Department>>() {
                        });
                        final Long deptId = Convert.toLong(fieldValue);
                        Optional<Department> department = departmentList.stream().filter(x -> x.getId().equals(deptId)).findFirst();
                        if (department.isPresent()) {
                            fieldValue = department.get().getName();
                        }
                        return fieldValue;
                    }
                }
                String datasourceType = MapUtils.getString(options, "datasourceType");
                boolean isCascade = StrUtil.equalsIgnoreCase(ComponentTypeConstant.CASCADE, componentType);
                //多选、选择、联想下拉、联想弹层、多选弹层、单选组件、级联组件
                if (StrUtil.equalsIgnoreCase(ComponentTypeConstant.CHECKBOX, componentType)
                        || StrUtil.equalsIgnoreCase(ComponentTypeConstant.SELECT, componentType)
                        || StrUtil.equalsIgnoreCase(ComponentTypeConstant.ASSOCIATE_SELECT, componentType)
                        || StrUtil.equalsIgnoreCase(ComponentTypeConstant.ASSOCIATE_POPUP, componentType)
                        || StrUtil.equalsIgnoreCase(ComponentTypeConstant.MULTIPLE_POPUP, componentType)
                        || StrUtil.equalsIgnoreCase(ComponentTypeConstant.RADIO, componentType)
                        || isCascade) {

                    if (!StrUtil.isEmpty(datasourceType) && StrUtil.equalsIgnoreCase(datasourceType, "dic")) {
                        String itemId = MapUtils.getString(options, "itemId");
                        List<DictionaryDetail> detailList = redisUtil.get(GlobalConstant.DIC_DETAIL_CACHE_KEY, new TypeReference<List<DictionaryDetail>>() {
                        });
                        //获取到对应字典的值
                        Map<String, Object> detailMap = detailList.stream().filter(x -> StrUtil.equalsIgnoreCase(x.getItemId().toString(), itemId))
                                .collect(Collectors.toMap(DictionaryDetail::getValue, DictionaryDetail::getName, (e1, e2) -> e1));
                        //获取字段的value值，转换为字典对应的name值进行输出
                        String[] valueArray = fieldValue.split(StringPool.COMMA);
                        for (int i = 0; i < valueArray.length; i++) {
                            if (detailMap.containsKey(valueArray[i])) {
                                valueArray[i] = detailMap.get(valueArray[i]).toString();
                            }
                        }
                    } else if ((!StrUtil.isEmpty(datasourceType) && StrUtil.equalsIgnoreCase(datasourceType, "api")) || isCascade) {//api或者级联组件
                        //获取转换后的字段值
                        fieldValue = getApiValue(fieldValue, options);
                    }
                    return fieldValue;
                }
                //前面的都不是就判断是不是岗位与行政区域
                if (TransType.POST.equals(componentType)) {
                    List<Post> postList = redisUtil.get(GlobalConstant.POST_CACHE_KEY, new TypeReference<List<Post>>() {
                    });
                    final Long postId = Convert.toLong(fieldValue);
                    Optional<Post> postOptional = postList.stream().filter(x -> x.getId().equals(postId)).findFirst();
                    if (postOptional.isPresent()) {
                        fieldValue = postOptional.get().getName();
                    }
                    return fieldValue;
                }
                if (StrUtil.equalsIgnoreCase(ComponentTypeConstant.AREA, componentType)) {
                    if (!StrUtil.isEmpty(fieldValue.toString())){
                        String[] valueArray = fieldValue.toString().split(StringPool.COMMA);
                        Set<Long> areaValueList = new LinkedHashSet<>();
                        areaValueList.addAll(Arrays.stream(valueArray).map(NumberUtils::toLong).collect(Collectors.toSet()));
                        IAreaService areaService = SpringUtil.getBean(IAreaService.class);
                        if (CollectionUtils.isNotEmpty(areaValueList)) {
                            List<Area> areaList = areaService.list(Wrappers.<Area>query().lambda().in(Area::getId, areaValueList));
                            for (String id : valueArray) {
                                Optional<Area> optionalArea = areaList.stream().filter(x -> x.getId().toString().equals(id)).findFirst();
                                if (tranValue.length() > 0) {
                                    tranValue.append(StringPool.SLASH);
                                }
                                if (optionalArea.isPresent()){
                                    tranValue.append(optionalArea.get().getName());
                                }
                            }
                        }
                    }
                    fieldValue = tranValue.toString();
                    return fieldValue;
                }
                if (StrUtil.equalsIgnoreCase(ComponentTypeConstant.MONEY_CHINESE, componentType)){//如果是货币大写组件，进行转换
                    //货币组件，去除后面的0
                    String valueString = NumberUtil.toStr(Double.valueOf(fieldValue.toString()));
                    //货币组件转大写
                    fieldValue = NumberChineseFormatter.format(Double.parseDouble(valueString),true);
                    return fieldValue;
                }
            }
        }
        return fieldValue;
    }


    /**
     * 获取api转换后的值
     * @param fieldValue 字段值
     * @param options
     * @return
     */
    private static String getApiValue(String fieldValue,Map<String, Object> options){
        List<Map<String, Object>> apiDataList = null;
        String apiId = MapUtils.getString(MapUtils.getMap(options, "apiConfig"), "apiId");
        IMagicApiService magicApiService = SpringUtil.getBean(IMagicApiService.class);
        Object resultApiData = magicApiService.executeApi(apiId);
        String apiValue = StringPool.EMPTY;
        if (resultApiData instanceof PageResult) {
            apiDataList = (List<Map<String, Object>>) ((PageResult) resultApiData).getList();
        } else if (resultApiData instanceof List) {
            apiDataList = (List<Map<String, Object>>) resultApiData;
        }
        if (apiDataList != null )  {
            Map<String, Object> collect = apiDataList.stream().filter(x -> ObjectUtil.isNotNull(x.get("value")))
                    .collect(Collectors.toMap(data -> data.get("value").toString(), data -> data.get("label"), (e1, e2) -> e1));
            //获取字段的value值，转换为api对应的label值进行输出
            String[] valueArray = fieldValue.split(StringPool.COMMA);
            for (int i = 0;i < valueArray.length;i++){
                if (collect.containsKey(valueArray[i])){
                    valueArray[i] = collect.get(valueArray[i]).toString();
                }
            }
            apiValue = StrUtil.join(StringPool.SLASH, valueArray);
        }
        return apiValue;
    }


    /**
     * 执行事件
     * @param processId 流程id
     * @param nodeEventConfigs 用户节点配置信息
     */
    public static void executeEvent(String processId,List<NodeEventConfig> nodeEventConfigs) {
        IMagicApiService magicApiService = SpringUtil.getBean(IMagicApiService.class);
        MagicAPIService magicAPIService = SpringUtil.getBean(MagicAPIService.class);

        ILiteflowChainService liteflowChainService = SpringUtil.getBean(ILiteflowChainService.class);
        FlowExecutor flowExecutor = SpringUtil.getBean(FlowExecutor.class);

        RuntimeService runtimeService = ProcessEngines.getDefaultProcessEngine().getRuntimeService();

        Object processParamObj = runtimeService.getVariable(processId, WorkflowConstant.PROCESS_PARAM_KEY);

        Object varObj = runtimeService.getVariables(processId);
        Map<String, Object> varMap = Convert.toMap(String.class, Object.class, varObj);
        Map<String, Object> processParam = Convert.toMap(String.class, Object.class, processParamObj);

        Object schemaIdObj = runtimeService.getVariable(processId, WorkflowConstant.PROCESS_SCHEMA_ID_KEY);
        Long schemaId = Convert.toLong(schemaIdObj);

        IWorkflowSchemaService workflowSchemaService = SpringUtil.getBean(IWorkflowSchemaService.class);
        WorkflowSchema workflowSchema = workflowSchemaService.getOne(Wrappers.lambdaQuery(WorkflowSchema.class).eq(WorkflowSchema::getId, schemaId));


        for (NodeEventConfig nodeEventConfig : nodeEventConfigs) {
            if (nodeEventConfig.getType() == WorkflowEventExType.API.getCode()) {
                ApiConfig apiConfig = nodeEventConfig.getApiConfig();
                MagicApiInfoVo info = magicApiService.info(apiConfig.getId());
                Map<String, Object> params = new HashMap<>();
                for (ApiRequestParamsConfig requestParamsConfig : apiConfig.getRequestParamsConfigs()) {
                    WorkFlowUtil.initApiParams(processParam, varMap, params, requestParamsConfig,workflowSchema,processId);
                }
                for (ApiRequestParamsConfig requestHeaderConfig : apiConfig.getRequestHeaderConfigs()) {
                    WorkFlowUtil.initApiParams(processParam, varMap, params, requestHeaderConfig,workflowSchema,processId);
                }
                for (ApiRequestParamsConfig requestBodyConfig : apiConfig.getRequestBodyConfigs()) {
                    WorkFlowUtil.initApiParams(processParam, varMap, params, requestBodyConfig,workflowSchema,processId);
                }
                magicAPIService.execute(info.getMethod(), info.getPath(), params);
            }else if (nodeEventConfig.getType() == WorkflowEventExType.MESSAGE.getCode()) {//消息推送
                MessageConfig messageConfig = nodeEventConfig.getMessageConfig();
                WorkflowSchemaConfig workflowSchemaConfig = JSONUtil.toBean(workflowSchema.getJsonContent(), WorkflowSchemaConfig.class);
                WorkFlowUtil.sendMessageCommon(messageConfig.getId(),messageConfig.getConfigs(),messageConfig.getReceiverConfiguration(),varMap,workflowSchemaConfig.getChildNodeConfig(),processId,null);
            }
            //如果是规则引擎
            else {

                LiteflowChain liteflowChain = liteflowChainService.getById(nodeEventConfig.getLiteflowId());
                flowExecutor.execute2Resp(liteflowChain.getChainName(), processParam);

            }

        }
    }


}

